1. 程式人生 > 其它 >記一次使用 SelectMany 的經歷

記一次使用 SelectMany 的經歷

最近在改造一個功能時為了減少迴圈的層數,於是想著將List列表對映為一個能直接使用顆粒大小的List列表,這樣一層迴圈就可以解決問題。

 public class ConflictWordItemForDisplay
{
/// <summary>
/// 基準欄位
/// </summary>
public string BasisField { get; set; }
/// <summary>
/// 關鍵字
/// </summary>
public string Keyword { get; set; }
/// <summary>
/// 衝突詞彙(支援多個詞彙,詞彙之間用,分隔)
/// </summary>
public string ConflictWord { get; set; }
/// <summary>
/// 判別欄位
/// </summary>
public List<string> JudgingFields { get; set; }

}

定義的資料類類似上面,在實際使用去進行判斷時可能需要用到三層迴圈,類似下面的虛擬碼

            foreach (var item in conflictWordItemForDisplayList)
            {
                if (基準欄位的內容.ToUpper().contains(item.Keyword.ToUpper()))
                {
                    foreach (var judgingField in item.JudgingFields)
                    {
                        
foreach (var word in item.ConflictWord.Split(',')) { if (judgingField對應的判別欄位的內容.ToUpper().contains(word.ToUpper())) { //衝突,進行對應的處理(提示使用者讓使用者修改之類) } } } } }

在判別欄位型別較少且固定時可以用判斷邏輯來減少一層迴圈。

如果用 SelectMany將粒度降到最小應該怎麼寫呢。微軟對SelectMany的描述是將序列的每個元素投影到 IEnumerable<T> 並將結果序列合併為一個序列。包括以下過載

將判別欄位降低到最小粒度:

            var allConflictWordItemForDisplay = conflictWordItemForDisplayList.SelectMany(p => p.JudgingFields, (s, r) => new ConflictWordItemForDisplay() { BasisField=s.BasisField,Keyword=s.Keyword,ConflictWord=s.ConflictWord,JudgingFields=new List<string> { r} });

將衝突詞彙降低到單獨一個詞彙的粒度:

allConflictWordItemForDisplay = allConflictWordItemForDisplay.SelectMany(p => p.ConflictWord.Split(','), (s, r) => new ConflictWordItemForDisplay() { BasisField = s.BasisField, Keyword = s.Keyword, ConflictWord = r, JudgingFields = s.JudgingFields });

這只是SelectMany適用於我這個問題的使用方式,SelectMany還有其他過載函式,使用到時可以詳細瞭解一下。

下面是微軟官方文件,裡面也有用例方便理解。

https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.6.1