【问题标题】:Optimizing C# loop comparison of two very large lists优化两个非常大的列表的 C# 循环比较
【发布时间】:2017-05-02 10:13:35
【问题描述】:

在你阅读我的解释之前,我想告诉你,我需要优化处理时间来比较两个巨大的 c# 列表,在嵌套循环中逐个索引。

它当然是我用 C# 创建的 .Net Core 应用程序。

在我的算法中,我必须创建一个很长的列表,其中包含一些整数范围,就像这样。

internal class Global
{
    public string ChromosomeName { get; set; }
    public int start { get; set; }
    public int end { get; set; }
    public string Cluster { get; set; }
    public string Data { get; set; }
} 
var globals = new List<Global>();// somewhere in my method.

现在这个列表将非常庞大,例如它会像这样存储值。这是我的主要列表,所以它被命名为“globals”

index 0 = start=1, end=400 ....
index 1 = start=401, end=800....
index (last) = start= 45090000 , end= 45090400 ...

这些只是粗略的估计值,以便您了解这将是一个庞大的列表。

现在在我的算法中我真正要做的是

  • 所以我获取了一个文本文件,读取该文件并将其数据存储在另一个列表中,该列表具有与上面代码中所示相同的属性。
  • 现在我有 2 个列表,全局列表和我从文件中读取的其他列表。
  • 它们都是非常庞大的列表
  • 现在我必须在嵌套循环中逐个索引比较它们。
  • 外循环将迭代我的全局列表,内循环将迭代我的另一个列表(我从文件中读取)。
  • 在完成一次嵌套循环后,我读取了另一个文件并创建了另一个列表,然后以相同的方式将该列表与全局列表进行比较..
  • 因此将有一个全局列表,将在嵌套循环中逐个索引地与大约 10 个列表进行比较,并且所有列表都几乎与全局列表本身一样大。

下面是嵌套 foreach 循环的伪代码。

foreach(var item in globals)
{
    var value=0;
    foreach(var item2 in otherHugeList)
    {
        compareMethod(item,item2);
        //below is the actual code of wht kind of comparison I am doing,     just if i guyx want to know, I am actually finding the overlap between two ranges.
       //value += Math.Max(0, Math.Min(range1.end, EndList[i]) -  Math.Max(range1.start, StartList[i]) + 1);
    }
}

我能做到这一点的最快方法是什么,因为现在它需要几个小时以上,我很沮丧,我取消了这个过程,因为我不知道它需要多长时间。所以我什至无法在较小的文件上得到结果。

我需要知道最快的方法来做到这一点,我应该使用任何与 .Net 核心兼容的库吗?或多线程以某种方式?不过我不太擅长线程概念。

P.S:我使用过 Parallel.ForEach,它的性能差异可以忽略不计。

【问题讨论】:

  • 这看起来/听起来像是 TPL 数据流的完美工作:msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx
  • 你已经说了你在做什么,但没有说你为什么这样做。比较这两个列表有什么意义?如果问题是“这些列表是否不同?”那么这比“有什么区别?”要快得多。
  • 你说的那些步骤我一个字都听不懂……你想做什么?好像是 XY 问题。
  • 如果您的结论“我必须逐个索引比较它们”是正确的,那么您只能通过改进比较项目的代码来提高速度。您提到范围,您能否将 erh“主列表”拆分为多个较小的列表,每个列表涵盖较小的范围?如果列表按示例中的范围排序,您可以“猜测”索引以开始查找匹配项。
  • 我会更新我的问题并正确解释步骤@M.kazemAkhgary

标签: c# list loops optimization .net-core


【解决方案1】:

如果您需要对两个列表进行逐个元素比较,每个列表包含 106 个项目,则需要进行 1012 个比较。它让你没有希望在理智的时间内完成,所以解决这个问题的关键是大幅减少比较次数。

减少的确切方法取决于您正在运行的比较类型,因此让我们以您帖子中的重叠计算为例。

当以下陈述之一为真时,您知道范围 R 和 Q 之间没有重叠:

  • R 的上限低于 Q 的下限,或
  • R 的下限高于 Q 的上限。

如果您的范围以随机顺序出现在列表中,这将无济于事。但是,如果您在下限对范围进行排序,并通过上限解决平局,您将能够使用二进制搜索来查找您比较的每个范围的列表的相关部分,即重叠的元素可能。

假设同一列表中的范围之间几乎没有重叠,这会将比较次数从每个元素大约一百万减少到每个元素不到一百,从而使性能提高 1000 倍。

我的列表都不会有自我重叠的范围(评论)

然后您可以使用merge algorithm 的变体,方法是对两个范围列表进行排序,然后在一个循环中对其进行迭代。将两个数组的索引设置为零,然后一次遍历两个列表。如果全局列表中的当前范围低于比较列表中当前范围的start 级别,则移动到全局列表的下一个元素;否则,转到比较列表的下一个元素。这两个索引将相互“追逐”,直到您在 2M 增量后到达两个列表的末尾。

【讨论】:

  • 你的答案是有道理的,而且我所有的范围都是排序的,你能告诉我一个二进制搜索的代码示例吗,我确实有排序的范围,但我不清楚我将如何使用二进制搜索找到上面提到的列表的相关部分。
  • 我了解您的合并算法逻辑,我明白了,我只有一个问题,两个列表中的元素数量不同,其中一个可能会出现索引越界错误完了,这种情况怎么处理?
  • @touseef 当其中一个列表的元素用完时,您就完成了,因为不再可能出现重叠。请注意,您的算法将比普通合并稍微复杂一些,因为当您看到重叠时,您需要探索两个列表以查看重叠何时结束。本质上,它是多对多匹配,例如10-20,21-30,31-4015-35,36-45 产生四个重叠,两边的元素匹配到另一边的多个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多