2016-03-09 105 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