根据另一个类型的另一个列表中的项目查找一个列表中的项目

时间:2020-06-05 17:30:15

标签: c# .net linq

我有一个List<Class1>List<Class2>,我想从List<Class1>中获取项目的ID在List<Class2>中的所有项目,反之,得到List<Class1>中没有{strong> ID 的项目中所有来自List<Class2>的项目。

public class Class1
{
    public int Id { get; set; }
    public string AnotherId { get; set; }
    public decimal Price { get; set; }
}

public class Class2
{
    public int Id { get; set; }
    public int AnotherId { get; set; }
    public string Message { get; set; }
}

我用Contains尝试了几种解决方案,但是找不到正确的方法。

4 个答案:

答案 0 :(得分:3)

您可以尝试这样的事情:

var result = list1.Where(x => list2.Any(y=>y.Id == x.Id))
                  .ToList();

即使两个列表都包含对相同类型对象的引用,Contains也无法立即使用。如果是这种情况,您将为类实现接口IEquatable或重写EqualsGetHashCode方法。只有这样Contains才能按预期工作。

答案 1 :(得分:0)

尝试这样的事情:

        foreach(var val in listClass2)
        {
            result.AddRange(listClass1.Where(l => l.id = val.id));
        }

答案 2 :(得分:0)

执行此操作的方法有多种,最简单的方法是使用System.LinqWhere()All()Any()方法:

var matchingIds = list1
    .Where(list1Item => list2.Any(list2Item => list2Item.Id == list1Item.Id))
    .ToList(); 

var nonMatching = list1
    .Where(list1Item => list2.All(list2Item => list2Item.Id != list1Item.Id))
    .ToList();

但是使用一个简单的循环也很容易:

var matchingIds = new List<Class1>();
var nonMatching = new List<Class1>();

foreach (var list1Item in list1)
{
    var foundMatch = false;

    foreach (var list2Item in list2)
    {
        if (list2Item.Id == list1Item.Id)
        {
            foundMatch = true;
            break;
        }
    }

    if (foundMatch)
    {
        matchingIds.Add(list1Item);
    }
    else
    {
        nonMatching.Add(list1Item);
    }
}

答案 3 :(得分:0)

如果列表中的项目较少,则Christos的答案是最简单的。但是,它是O(n ^ 2)算法。如果列表中有相当数量的项目(甚至数千个项目),那么该算法将大大减慢速度。让我们尝试一个示例:

    List<Class1> list1 = new List<Class1>();
    List<Class2> list2 = new List<Class2>();

    const int ITEMS_TO_ADD = 30000;

    for (int i=1; i<= ITEMS_TO_ADD; i++)
    {
        list1.Add(new Class1 { Id = i });
        list2.Add(new Class2 { Id = i });
    }

    for (int i = 1; i <= ITEMS_TO_ADD; i++)
    {
        list1.Add(new Class1 { Id = -i });
    }

    Stopwatch sw = new Stopwatch();
    sw.Start();                        
    var result = list1.Where(x => list2.Any(y => y.Id == x.Id)).ToList();
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);

在我的机器上,大约需要30秒。

再次,一个更好的解决方案是,如果您拥有适当大小的数据集,将是这样的:

HashSet<int> list2Keys = new HashSet<int>(list2.Select(x => x.Id));
var resultInList2 = list1.Where(x => list2Keys.Contains(x.Id)).ToList();

在我的机器上耗时约10毫秒。

当然,要使项目不在列表2中,只需将行更改为

var resultInList2 = list1.Where(x => !list2Keys.Contains(x.Id)).ToList();

这当然是O(n),而不是O(n ^ 2)