【问题标题】:Optimization of nested loops using LINQ使用 LINQ 优化嵌套循环
【发布时间】:2016-06-23 17:38:20
【问题描述】:

您能否建议如何为以下操作编写优化的 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 是我在不区分大小写的情况下比较字符串的扩展方法。

【问题讨论】:

  • 你想优化什么?可读性,还是性能?我认为两者都不会改善。
  • 性能。我无法给出确切的代码。我知道这可能很难阅读,但您可以重命名变量以适合自己。
  • 您为什么期望手动内存处理与 linq 内存处理在性能方面有所不同?
  • 我正在探索更好地运行代码的可能性。原始代码在涉及的特定大小的数据库上需要 4 分钟以上。
  • 优化最好使用手头的分析器工具来完成。然后你就会知道要重构或重写 linq 的哪一部分。

标签: c# .net performance linq datatable


【解决方案1】:

显然瓶颈是线路

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);
}

【讨论】:

  • 我会试一试并报告。谢谢!
  • 太棒了!!!这行得通!我的电脑上最初的操作时间是 2 分 40 秒。您的算法在 29 秒内以相同的输出在同一台 PC 上完成!太感谢了!我学到了很多!
猜你喜欢
  • 1970-01-01
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 2015-05-29
  • 2020-05-18
  • 1970-01-01
相关资源
最近更新 更多