Using LINQ to get the difference between two list of objects based only on a single object property [closed]

非 Y 不嫁゛ 提交于 2020-01-23 11:41:06

问题


the dog class has two properties (name and color)

Let's say I have two IEnumerable lists:

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

I want to get a list of dog objects that differ ONLY in name

so my return list would look like

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

Make Sense?

I want to do this with linq. This is what I've tried... and it's not working any help?

  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;

I may be a complete moron, but I've stared at this all day and can't get it. any help would be appreciated.


回答1:


What you have is functionally Except, but instead of using equality of the whole item, you want to perform the Except using a selected property as the key. While you could provide a custom IEqualityComparer to Except that only compared names, writing that comparer is a fair bit of error prone boilerplate code. We can write a method that performs an Except on a projected key fairly easily:

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

This performs an except using the given key, instead of a custom equality comparer.

Now your query is simply:

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



回答2:


You could separated the list of the names that you do not want. After this, you could use Any with ! (not) operator to filter the names out of this list. For sample:

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



回答3:


The longest solution

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

}



来源:https://stackoverflow.com/questions/28224156/using-linq-to-get-the-difference-between-two-list-of-objects-based-only-on-a-sin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!