代码之家  ›  专栏  ›  技术社区  ›  少強甘

如何在两种不同类型上使用Except?

  •  0
  • 少強甘  · 技术社区  · 1 年前

    我可以使用 Except() 在两种相同类型上,如:

    var list1 = new List<int> { 1 , 2 , 3 , 5 , 9 };
    var list2 = new List<int> { 4 , 3 , 9 };
    
    var expectedList = list1.Except(list2);//Result:  { 1 , 2 , 5 }
    

    但是如何处理不同的类型呢?比如:

    var cats = new List<Cat>();
    var dogs = new List<Dog>();
    
    var exceptCats = cats
                 .Except(dogs)
                 .On(cat.Age == dog.Age && cat.Name == dogs.Name)
    
    3 回复  |  直到 1 年前
        1
  •  2
  •   Yong Shun    1 年前

    使用 Except() 用于排除第一集合和第二集合,两者都是 相同的 类型

    您可以使用 .Where() 在这种情况下过滤具有相同行为的。

    var exceptCats = cats.Where(cat => !dogs.Any(dog => cat.Age == dog.Age && cat.Name == dog.Name))
        .ToList();
    
        2
  •  2
  •   Svyatoslav Danyliv    1 年前

    最具性能的是使用 GroupJoin

    var exceptCats = 
        from cat in cats
        join dog in dogs 
           on new { cat.Age, cat.Name } equals { dog.Age, dog.Name } into gj
        where !gj.Any()
        select cat;
    
        3
  •  2
  •   Guru Stron    1 年前

    您可以使用 Where 方法,但对于相对较大的集合,这可能会导致性能成本。若要解决此问题,您可以为特定用例创建自定义相等比较器。如果这两种类型都没有共享类型/接口(基类/接口),则可能如下所示:

    class CatDogComparer : IEqualityComparer<object>
    {
        public bool Equals(object x, object y)
        {
            return (x, y) switch
            {
                (Dog d, Cat c) => Compare(d, c),
                (Cat c, Dog d) => Compare(d, c),
                _ => false
            };
    
            bool Compare(Dog d, Cat c) => d.Age == c.Age && d.Name == d.Name;
        }
    
        public int GetHashCode(object obj) => obj switch
        {
            Dog d => HashCode.Combine(d.Age, d.Name),
            Cat c => HashCode.Combine(c.Age, c.Name),
            _ => obj.GetHashCode() // throw?
        };
    }
    

    以及用法:

    var exceptCats = cats
        .Except(dogs, new CatDogComparer())
        .ToList();
    

    这可以通过引入一些共享类型来改进,例如:

    public interface IHaveNameAndAge
    {
        int Age { get; set; }
        string Name { get; set; }
    }
    
    public class Cat : IHaveNameAndAge {...}
    public class Dog : IHaveNameAndAge {...}
    

    另一种方法是使用LINQ(据我所知,它也应该进行优化):

    var catsToExclude = from c in cats
        join d in dogs on new { c.Age, c.Name } equals new { d.Age, d.Name }
        select c;
    
    var exceptCats = cats
        .Except(catsToExclude)
        .ToList();
    
        4
  •  0
  •   Peter B    1 年前

    让我们换个说法:你想要所有没有狗的猫都有相同的名字和年龄。

    这样说,你需要使用的Linq几乎是自然而然的:

    var cats = new List<Cat>();
    var dogs = new List<Dog>();
    
    var exceptCats = cats.Where(cat => !dogs.Any(dog => cat.Age == dog.Age && cat.Name == dog.Name));
    
    推荐文章