LINQ筆記:將兩個IEnumerable List(T)集合物件內容相加

今天剛好有個需求,需要將兩個List<string>進行疊加後再進行相關處理,由於之前沒有做過這方面的程式碼,因此在網路爬了一些知識,補充在這個地方。

假設我們今天有兩個List<string>分別為oListA與oListB,其值詳見下列程式碼:

System.Collections.Generic.List<string> oListA = new List<string>() { "AAA", "BBB", "CCC" };
System.Collections.Generic.List<string> oListB = new List<string>() { "CCC", "DDD", "EEE" };

使用AddRange()方法

oListA可以使用AddRange()方法,來將oListB的內容疊加入oListA,這樣的做法的缺點是oListA原本的內容會被異動,在某些情況下這可被視為汙染,要不要用就看你自己的選擇了。語法如下:

oListA.AddRange(oListB);

在這行指令之後,你去foreach oListA會得到6個內容值的List<string>,分別為AAA、BBB、CCC、CCC、DDD、EEE。

使用Concat()方法

oListA可以使用Concat()方法,將oListB的內容相加後拋出一個全新的IEnumerable<string>,如果以這篇文章的標題來看,這樣的作法將會獲得最佳的效率且不汙染原本的oListA與oListB(搞不好你的程式碼之後還需要用到這兩個集合)。

var oListC = oListA.Concat(oListB);

在這行指令之後,你去foreach oListC會得到6個內容值的IEnumerable<string>,分別為AAA、BBB、CCC、CCC、DDD、EEE。而oListA的內容依然保持為3個內容值。

使用Union()方法

基本上Union()方法與Concat()方法雷同,但是他會將兩個集合中重複的元素排除,所以如果你在疊加的結果中希望排除重複的元素,那麼這個指令會非常的適合你。

var oListC = oListA.Union(oListB);

在這行指令之後,你去foreach oListC會得到5個內容值的IEnumerable,分別為AAA、BBB、CCC、DDD、EEE。

補充說明:針對IEnumerable<T>的null檢查

上面的LINQ方法看起來操作非常簡單,但裡面卻藏著一個小坑,那就是你必須確保oListA、oListB等集合物件不可為null,這時候會有人建議你採用DefaultIfEmpty<T>,可是這個DefaultIfEmpty必須指定一個非null的預設值,有時候反而會汙染我們要的集合物件。例如:

System.Collections.Generic.List<string> oFiles = new List<string>() { 
  "DoNotDeleteAAA.txt",
  "DoNotDeleteBBB.txt",
  "DoNotDeleteCCC.txt",
};
//篩選出想要刪除的檔案以利刪除
var oWannaDelete = oFiles.Where(x => !x.StartsWith("DoNot")).Select(x => x).DefaultIfEmpty("NoFiles!");.

從上面的程式碼可以看到,如果我們想要利用DefaultIfEmpty方法來避免null的話,那麼只會落入更尷尬的處境,例如我們認為oWannaDeleter就是我要刪除的檔案列表,當我們真的去執行刪除動作但當下並沒有適合刪除的檔案時,大不了就不執行離開了。但以這個例子來說,程式碼可能會想要去針對一個不存在的「NoFiles!」檔案進行刪除。

在這種狀況使用DefaultIfEmpty()方法,簡直是拿石頭砸自己的腳。

比較恰當的使用方式是採用??運算子(null運算子)以及System.Linq.Enumerable.Empty<T>來進行空集合的指派,詳見下列範例程式碼(以上述Concat()方法為例子,進行null檢查修補):

var oListC = (oListA ?? System.Linq.Enumerable.Empty()).Concat(oListB ?? System.Linq.Enumerable.Empty());

這樣的寫法在最倒楣的情況下,oListA、oListB經過Linq運算均Select出null,仍然可以安全的保證疊加出一個oListC空集合。

C# LINQ List(int) List(string) Add Combine Lists System.Collections.Generic Null Check