我有两个大型列表,我需要得到它们之间的差异

时间:2017-12-13 11:09:25

标签: c# performance list linq loops

我有两个大型列表,我需要在它们之间获得差异。

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

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

有另一种性能最佳的解决方案吗?

使用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();

4 个答案:

答案 0 :(得分:4)

您可以使用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);
    }
{

答案 1 :(得分:1)

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

Else最好使用内连接并发出

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

如果dblist

中没有给定数据,它将选择列表

答案 2 :(得分:1)

HashSet<T>已针对执行此类设置操作进行了优化。在许多情况下,值得努力从列表创建HashSet并在Hashsets上执行set操作。我用一点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 

因此创建HashSets并执行ExceptWith(一起0.18),击败Except(0.26s)。

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

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

答案 3 :(得分:0)

使用List.Exists,优于List.Any 效果