使用LINQ仅基于单个对象属性获取两个对象列表之间的差异

时间:2015-01-29 20:39:20

标签: c# linq linq-to-objects

狗类有两个属性(名称和颜色)

我们说我有两个IEnumerable列表:

List1 [{name="Sam", color="Fawn"}, {name="Mary", color=""}, {name="Bob", color=""}]
List2 [{name="Mary", color="Black"},{name="Bob", color="Yellow"}]

我想得到一个只在名称

上有所不同的狗对象列表

所以我的返回列表看起来像

ListReturn: [{name="Sam", color="Fawn"}]

有意义吗?

我想用linq做这件事。这就是我尝试过的......而且它没有用 有什么帮助吗?

  var missing = from l1 in List1
                join l2 in List2 on l1.Name equals l2.Name into merged
                from missed in merged.DefaultIfEmpty()
                select missed;

我可能是一个完整的白痴,但我一整天都盯着这一点而无法得到它。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:9)

您拥有的功能是Except,但您不想使用整个项目的相等性,而是希望使用所选属性作为键来执行Except。虽然您可以提供只对比名称的自定义IEqualityComparerExcept,但编写该比较器是一个容易出错的样板代码。我们可以编写一种方法,可以非常轻松地对投影键执行Except

public static IEnumerable<TSource> ExceptBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    IEnumerable<TSource> other,
    Func<TSource, TKey> keySelector)
{
    var set = new HashSet<TKey>(other.Select(keySelector));
    foreach(var item in source)
        if(set.Add(keySelector(item)))
            yield return item;
}

执行使用给定键的except,而不是自定义相等比较器。

现在您的查询只是:

var query = list1.ExceptBy(list2, dog => dog.name);

答案 1 :(得分:2)

您可以分隔出您不想要的名称列表。在此之后,您可以使用Any!(非)运算符来过滤此列表中的名称。样本:

var l2Names = List2.Select(x => x.Name);
var missing = from l1 in List1                  
              where !l1.Any(x => l2Names.Contains(x.Name))
              select l1;

答案 2 :(得分:0)

最长的解决方案

private static void Main(string[] args)
{
    var dogs1 = new List<Dog>
    {
        new Dog{Name = "Sam", Color = "Fawn"},
        new Dog{Name = "Mary", Color = ""},
        new Dog{Name = "Bob", Color = ""}
    };

    var dogs2 = new List<Dog>
    {
        new Dog{Name = "Mary", Color = "Black"},
        new Dog{Name = "Bob", Color = "Yellow"}
    };

    var comparer = new Comparer();

    var common = dogs1.Intersect(dogs2, comparer).ToList();

    var res = dogs1.Except(common, comparer)

        .Union(dogs2.Except(common, comparer));
}

public class Dog : INameable
{
    public string Name { get; set; }
    public string Color { get; set; }
}

public interface INameable
{
    string Name { get; }
}

public class Comparer : IEqualityComparer<INameable>
{
    public bool Equals(INameable x, INameable y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(INameable obj)
    {
        return obj.Name.GetHashCode();
    }
}

}