2016-03-09 106 views
1

您能否建議如何爲以下操作編寫優化LINQ查詢?使用LINQ優化嵌套循環

foreach (DataRow entry1 in table1.Rows) 
{ 
    var columnA = entry1["ColumnA"] as string; 
    if (!string.IsNullOrEmpty(columnA)) 
    { 
     foreach (string entry2 in table2) 
     { 
      var dataExists = table3.Any(rows3 => 
       !string.IsNullOrEmpty(rows3[entry2] as string) 
       && columnA.IsEqual(rows3["ColumnB"] as string)); 
      if (dataExists) 
      { 
       entry1[entry2] = Compute(columnA, entry2); 
      } 
     } 
    } 
} 

我試過這個,但結果在獨特的迭代計數方面不匹配。

var t2t3Pair = from entry2 in table2 
    let entry3 = table3.FirstOrDefault(x => 
     !string.IsNullOrEmpty(x[entry2] as string)) 
    where entry3 != null 
    select new { entry2, entry3 }; 

var t1t3Pair = from pair in t2t3Pair 
    from entry1 in table1.AsEnumerable() 
    let columnA = entry1["ColumnA"] as string 
    where !string.IsNullOrEmpty(columnA) 
     && columnA.IsEqual(pair.entry3["ColumnB"] as string) 
    select new { Entry1Alias = entry1, Entry2Alias = pair.entry2 }; 

foreach (var pair in t1t3Pair) 
{ 
    var columnA = (string)pair.Entry1Alias["ColumnA"]; 
    pair.Entry1Alias[pair.Entry2Alias] = Compute(columnA, pair.Entry2Alias); 
} 

注:IsEqual是我的擴展方法不區分大小寫比較字符串。

+0

什麼是你想優化?可讀性還是性能?我認爲這兩者都不會改善。 – Maarten

+0

表現。我無法給出確切的代碼。我知道這可能很難閱讀,但您可以重新命名變量以適合自己。 – Nayan

+0

您爲什麼期望手動內存處理是linq內存中處理的任何不同的執行方式? – Maarten

回答

2

顯然的瓶頸是其最裏面的循環中執行的行

var dataExists = table3.Any(rows3 => 
    !string.IsNullOrEmpty(rows3[entry2] as string) 
    && columnA.IsEqual(rows3["ColumnB"] as string)); 

。與往常一樣,它可以通過預先準備快速查找數據結構並在關鍵循環內部使用它進行優化。

對於你的情況,我建議是這樣的:

var dataExistsMap = table3.AsEnumerable() 
    .GroupBy(r => r["ColumnB"] as string) 
    .Where(g => !string.IsNullOrEmpty(g.Key)) 
    .ToDictionary(g => g.Key, g => new HashSet<string>(
     table2.Where(e => g.Any(r => !string.IsNullOrEmpty(r[e] as string))) 
    // Include the proper comparer if your IsEqual method is using non default string comparison 
    //, StringComparer.OrdinalIgnoreCase 
    ) 
); 

foreach (DataRow entry1 in table1.Rows) 
{ 
    var columnA = entry1["ColumnA"] as string; 
    if (string.IsNullOrEmpty(columnA)) continue; 
    HashSet<string> dataExistsSet; 
    if (!dataExistsMap.TryGetValue(columnA, out dataExistsSet)) continue; 
    foreach (string entry2 in table2.Where(dataExistsSet.Contains)) 
     entry1[entry2] = Compute(columnA, entry2); 
} 
+0

我會試一試並回報。謝謝! – Nayan

+0

太棒了!這工作!我在PC上的原始時間是2分40秒。您的算法在同一臺PC上以29秒完成相同輸出!非常感謝!我學到了很多! – Nayan