最近在改造一個功能時為了減少迴圈的層數,於是想著將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