LINQ筆記:將兩個IEnumerable List集合物件內容相加
今天剛好有個需求,需要將兩個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的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空集合。