【问题标题】:Best Way to compare 1 million List of object with another 1 million List of object in c#将 100 万个对象列表与 c# 中的另外 100 万个对象列表进行比较的最佳方法
【发布时间】:2020-04-26 23:30:06
【问题描述】:

我将 100 万个对象列表与另外 100 万个对象列表区分开来。 我正在使用 for , foreach 但迭代这些列表需要太多时间。 任何人都可以帮助我做到这一点的最佳方法

var SourceList = new List<object>(); //one million 
var TargetList = new List<object>()); // one million

//getting data from database here
//SourceList with List of one million 
//TargetList with List of one million

var DifferentList = new List<object>();

//ForEach
SourceList.ToList().ForEach(m =>
    {
      if (!TargetList.Any(s => s.Name == m.Name))
            DifferentList.Add(m);
  });

 //for
 for (int i = 0; i < SourceList .Count; i++)
   {
    if (!TargetList .Any(s => s == SourceList [i].Name))
            DifferentList .Add(SourceList [i]);
  }



【问题讨论】:

  • 发布一些代码。这会很有帮助。
  • 首先不是C#的问题,而是普遍的问题。根据您的结构,您可以使用排序列表或二叉树...
  • 比较对象的依据是什么?
  • 您可以将列表拆分成更小的块并并行运行您的操作吗?
  • 在 Stack Overflow 上提问时的一个建议:积极响应,参与其中!如有必要,回复您收到的答案,以便回复者知道他们在正确的轨道上,并始终回复 cmets 中的问题或建议。

标签: c# asp.net-mvc linq for-loop foreach


【解决方案1】:

我认为这似乎是个坏主意,但 IEnumerable 魔法会帮助你。

首先,简化您的表达方式。它看起来像这样:

var result = sourceList.Where(s => targetList.Any(t => t.Equals(s)));

我建议在Equals 方法中进行比较:

public class CompareObject
{
    public string prop { get; set; }

    public new bool Equals(object o)
    {
        if (o.GetType() == typeof(CompareObject))
            return this.prop == ((CompareObject)o).prop;    
        return this.GetHashCode() == o.GetHashCode();
    }
}    

接下来添加AsParallel。这可以加快和减慢您的程序。在您的情况下,您可以添加...

var result = sourceList.AsParallel().Where(s => !targetList.Any(t => t.Equals(s)));

如果您尝试像这样一次列出所有内容,CPU 100% 已加载:

var cnt = result.Count();

但如果你得到小部分的结果,工作是可以忍受的。

result.Skip(10000).Take(10000).ToList();

完整代码:

static Random random = new Random();
public class CompareObject
{
    public string prop { get; private set; }

    public CompareObject()
    {
        prop = random.Next(0, 100000).ToString();
    }

    public new bool Equals(object o)
    {
        if (o.GetType() == typeof(CompareObject))
            return this.prop == ((CompareObject)o).prop;    
        return this.GetHashCode() == o.GetHashCode();
    }
}

void Main()
{
    var sourceList = new List<CompareObject>();
    var targetList = new List<CompareObject>();
    for (int i = 0; i < 10000000; i++)
    {
        sourceList.Add(new CompareObject());
        targetList.Add(new CompareObject());
    }

    var stopWatch = new Stopwatch();

    stopWatch.Start();
    var result = sourceList.AsParallel().Where(s => !targetList.Any(t => t.Equals(s)));


    var lr = result.Skip(10000).Take(10000).ToList();
    stopWatch.Stop();

    Console.WriteLine(stopWatch.Elapsed);
}

更新

我记得你可以使用Hashtable。从targetListsourceList 中选择唯一值,然后填写值不是targetList 的结果。

例子:

static Random random = new Random();
public class CompareObject
{
    public string prop { get; private set; }
    public CompareObject()
    {
        prop = random.Next(0, 1000000).ToString();
    }

    public new int GetHashCode() {
        return prop.GetHashCode();
    }
}


void Main()
{
    var sourceList = new List<CompareObject>();
    var targetList = new List<CompareObject>();
    for (int i = 0; i < 10000000; i++)
    {
        sourceList.Add(new CompareObject());
        targetList.Add(new CompareObject());
    }

    var stopWatch = new Stopwatch();

    stopWatch.Start();
    var sourceHashtable = new Hashtable();
    var targetHashtable = new Hashtable();

    foreach (var element in targetList)
    {
        var hash = element.GetHashCode();
        if (!targetHashtable.ContainsKey(hash))
            targetHashtable.Add(element.GetHashCode(), element);
    }

    var result = new List<CompareObject>();
    foreach (var element in sourceList)
    {
        var hash = element.GetHashCode();
        if (!sourceHashtable.ContainsKey(hash))
        {
            sourceHashtable.Add(hash, element);
            if(!targetHashtable.ContainsKey(hash)) {
                result.Add(element);
            }
        }
    }

    stopWatch.Stop();

    Console.WriteLine(stopWatch.Elapsed);
}

【讨论】:

    【解决方案2】:

    扫描目标列表以匹配名称是一个 O(n) 操作,因此您的循环是 O(n^2)。如果你为目标列表中的所有不同名称构建一个HashSet&lt;string&gt;,你可以使用 Contains 方法在 O(1) 时间内检查集合中是否存在一个名称。

    【讨论】:

      【解决方案3】:

      //这里从数据库中获取数据

      您正在将数据输出一个专门用于匹配、排序和过滤数据的系统,输入您的 RAM,默认情况下根本无法执行该任务。然后你尝试对自己进行排序、过滤和匹配。

      那将失败。无论您多么努力,您的计算机极不可能只有一个程序员在匹配算法上工作,在该软件应该非常擅长的一次操作中,它的性能将胜过称为数据库服务器的专用硬件。由专家团队和多年优化。

      你不会去一家高档餐厅,要求他们给你一大袋原料,这样你就可以把它们扔进一个没有剥皮的大碗里,然后在家里用微波炉加热。不。你点了一道好菜,因为它比你自己做的任何事情都要好。

      简单的答案是:不要这样做。不要拿原始数据在里面翻找几个小时。将该工作留给数据库。这是它应该擅长的一件事。使用它的力量。写一个查询会给你结果,不要获取原始数据然后自己玩数据库。

      【讨论】:

      • 在某些情况下(例如 MVVM),您可能只使用模型对象而不访问数据库。
      • 在 MVVM 中没有规定您必须通过不使用数据库来故意削弱程序。您可以在模型中使用一个方法来查询数据库并返回结果列表。
      【解决方案4】:

      Foreach 在每次迭代之前都会执行一次空值检查,因此使用标准的 for 循环将提供更好的性能,这是难以超越的。

      如果花费的时间太长,您能否将集合分解为更小的集合和/或并行处理它们?

      你也可以使用.AsParallel()查看PLinq (Parallel Linq)

      其他需要改进的方面是您正在使用的实际比较逻辑,以及数据在内存中的存储方式,根据您的问题,您可能不必每次迭代都将整个对象加载到内存中。

      请提供代码示例,以便我们进一步提供帮助,当涉及如此大量的数据时,性能下降是可以预料的。

      再次根据我们在这里讨论的时间,您可以将数据上传到数据库中并使用它进行比较,而不是尝试在 C# 中本地进行,这种类型的解决方案更适合数据集已经在数据库中,或者数据更改的频率远低于执行比较所需的时间。

      【讨论】:

        猜你喜欢
        • 2012-02-27
        • 2015-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-06
        相关资源
        最近更新 更多