【问题标题】:I have two large lists and I need get the diff between them我有两个大列表,我需要了解它们之间的差异
【发布时间】:2017-12-13 11:09:25
【问题描述】:

我有两个大列表,我需要了解它们之间的差异。

第一个列表来自另一个系统通过 web 服务,第二个列表来自数据库(数据的命运)。

我将从第一个列表中比较并获取第二个列表中没有的项目并插入到数据库中(第二个列表源)。

还有其他性能最佳的解决方案吗?

使用List.Any(),这个过程需要很多小时并且没有完成......

使用for循环,这个过程需要10个小时或更长时间。

每个列表有 1.300.000 条记录

newItensForInsert = List1.Where(item1 => !List2.Any(item2 => item1.prop1 == item2.prop1 && item1.prop2 == item2.prop2)).ToList();

//or
for (int i = 0; i < List1.Count; i++)
{
    if (!List2.Any(x => x.prop1 == List1[i].prop1 && x.prop2 == List1[i].prop2))
    {
        ListForInsert.Add(List1[i]);
    }
}

//or
ListForInsert =  List1.AsParallel().Except(List2.AsParallel(), IEqualityComparer).ToList();

【问题讨论】:

  • 你能告诉我们你的代码吗?
  • 您的列表有多大?适合您 RAM 的东西绝不应该花费“数小时”才能发现它与另一个对象相同。
  • 显示您的代码或发布MCV 示例以便我们更好地理解。
  • 多大是多大?让我们知道这两个列表的计数是多少。这实际上很重要。您正在使用一种非常幼稚、简单的方法,只使用一个线程。当然,这需要几个小时......!!!此外,列表本身的性质也很重要。比较方式会根据它们是否严格正交而有所不同。
  • 已添加代码,请参阅

标签: c# performance list linq loops


【解决方案1】:

你可以使用 List.Except

List<object> webservice = new List<object>();
List<object> database = new List<object>();
IEnumerable<object> toPutIntoDatabase = webservice.Except(database);

database.AddRange(toPutIntoDatabase);

编辑:

你甚至可以像这样使用新的 PLINQ(并行 LINQ)

IEnumerable<object> toPutIntoDatabase = webservice.AsParallel().Except(database.AsParallel());

编辑:

也许您可以使用 Hashset 来加快查找速度。

HashSet<object> databaseHash = new HashSet<object>(database);

foreach (var item in webservice)
{
    if (databaseHash.Contains(item) == false)
    {
        database.Add(item);
    }
{

【讨论】:

  • 我也尝试使用Except,但没有解决我的问题,需要很长时间处理。
  • 我已经编辑了答案,也许查找表可以帮助?
【解决方案2】:

如果数据类型相同,则可以使用 List.Exists,

否则最好使用内部连接和发射

var newdata = from c in dblist
join p in list1 on c.Category  equals p.Category into ps
from p in ps.DefaultIfEmpty()

如果给定的数据不在 dblist 中,它将选择列表

【讨论】:

  • 你知道如何在 'equals' 中使用 2 个条件吗?
【解决方案3】:

HashSet&lt;T&gt; 针对执行这种集合操作进行了优化。在许多情况下,从列表创建 HashSet 并对 Hashset 执行集合操作是值得的。我用一个小的 Linqpad 程序演示了这一点。

程序创建两个包含 1,300,000 个对象的列表。它使用您的方法来获得差异(或者更好:尝试使用,因为我没有耐心了)。它使用 LINQ 的 Except 和带有 ExceptWith 的哈希集,两者都带有 IEqualityComparer。该程序如下所列。

结果是:

Lists created: 00:00:00.9221369 
Hashsets created: 00:00:00.1057532 
Except: 00:00:00.2564191 
ExceptWith: 00:00:00.0696830 

因此,创建 HashSet 并执行 ExceptWith(总共 0.18),击败 Except(0.26 秒)。

一个警告:创建 HashSet 可能会占用太多内存,因为大型列表已经占用了相当多的内存。

void Main()
{
    var sw = Stopwatch.StartNew();
    var amount = 1300000;
    //amount = 50000;
    var list1 = Enumerable.Range(0, amount).Select(i => new Demo(i)).ToList();
    var list2 = Enumerable.Range(10, amount).Select(i => new Demo(i)).ToList();
    sw.Stop();
    sw.Elapsed.Dump("Lists created");
    sw.Restart();


    var hs1 = new HashSet<Demo>(list1, new DemoComparer());
    var hs2 = new HashSet<Demo>(list2, new DemoComparer());
    sw.Stop();
    sw.Elapsed.Dump("Hashsets created");
    sw.Restart();

//    var list3 = list1.Where(item1 => !list2.Any(item2 => item1.ID == item2.ID)).ToList();
//    sw.Stop();
//    sw.Elapsed.Dump("Any");
//    sw.Restart();

    var list4 = list1.Except(list2, new DemoComparer()).ToList();
    sw.Stop();
    sw.Elapsed.Dump("Except");
    sw.Restart();
    hs1.ExceptWith(hs2);
    sw.Stop();
    sw.Elapsed.Dump("ExceptWith");

//    list3.Count.Dump();
    list4.Count.Dump();
    hs1.Count.Dump();
}

// Define other methods and classes here
class Demo
{
    public Demo(int id)
    {
        ID = id;
        Name = id.ToString();
    }
    public int ID { get; set; }
    public string Name { get; set; }
}

class DemoComparer : IEqualityComparer<Demo>
{
    public bool Equals(Demo x, Demo y)
    {
        return (x == null && y == null)
            || (x != null && y != null) && x.ID.Equals(y.ID);
    }

    public int GetHashCode(Demo obj)
    {
        return obj.ID.GetHashCode();
    }
}

【讨论】:

  • 仅供参考,运行包含 50000 个项目的程序,您的方法需要 17 秒。
  • 也许您最好的选择是立即将列表作为 Hashset 获取,这样您就不必再将它们转换为 Hashset。但是,我很惊讶看到您的评论,除了也很慢。我开始怀疑在 except 操作期间会触发大量延迟加载。您能否提供所涉及的实际对象的详细信息?
【解决方案4】:

使用List.Exists,比List.Any性能方面

【讨论】:

  • MSDN 说:“此方法执行线性搜索;因此,此方法是 O(n) 操作,其中 n 是 Count。”对于 List.Exists。你认为 Enumerable.Any 做得比这更糟吗? :D
猜你喜欢
  • 2020-09-17
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-28
相关资源
最近更新 更多