【问题标题】:Comparing a collection of reference type objects for equality ignoring order of items in collection比较引用类型对象的集合是否相等,忽略集合中项目的顺序
【发布时间】:2022-01-04 02:43:49
【问题描述】:

我有以下示例类

public class Item
{
    public string name { get; set; }
    public double price { get; set; }
}

public class Basket
{
    public Item[] items;
}

然后我创建了两个Basket 实例,都包含Items

var basket1 = new Basket()
{
   items = new Item[]
   {
       new Item() { name = "bread", price = 1.5 },
       new Item() { name = "butter", price = 2 }
   }
};

var basket2 = new Basket()
{
   items = new Item[]
   {
       new Item() { name = "butter", price = 2 },
       new Item() { name = "bread", price = 1.5 }
   }
};

我想比较 Basket1Basket2,忽略篮子中项目的顺序。比较时,此示例应返回 True(它们相等)。我应该如何进行?

【问题讨论】:

标签: c# arrays object compare equality


【解决方案1】:

@Neil 的答案是正确的,只是它不适用于引用类型(字符串是一个例外,因为它们是不可变的)。

Item 是一个类,所以它是一个引用类型。

Except 使用默认的相等比较器来比较元素。由于 Item 是一个类,它会通过引用进行比较,这不是我们想要的解决方案。所以我们需要绕过默认比较,使用自定义相等比较器。为此目的存在Except 的重载。

您需要创建一个实现IEqualityComparer<Item> 的类型并将该类型的实例传递给Except

请参阅:Except overload documentationIEqualityComparer documentation

这是一个可以在 Linqpad 中运行的示例。它同时使用Except 重载。一个返回false,另一个返回true

void Main()
{
    var basket1 = new Basket()
    {
        items = new Item[]
   {
       new Item() { name = "bread", price = 1.5 },
       new Item() { name = "butter", price = 2 }
   }
    };

    var basket2 = new Basket()
    {
        items = new Item[]
       {
       new Item() { name = "butter", price = 2 },
       new Item() { name = "bread", price = 1.5 }
       }
    };
    
    var isIdenticalByReference = (!(basket1.items.Except(basket2.items).Any())); // false
    isIdenticalByReference.Dump();
    
    var isIdenticalWithCustomEqualityComparer = (!(basket1.items.Except(basket2.items, new ItemEqualityComparer()).Any())); // true
    isIdenticalWithCustomEqualityComparer.Dump();
}

// You can define other methods, fields, classes and namespaces here

public class Item
{
    public string name { get; set; }
    public double price { get; set; }

    public int GetHashCode(object obj)
    {
        return (name?.GetHashCode() ?? 0) ^ price.GetHashCode();
    }
}

public class ItemEqualityComparer : IEqualityComparer<Item>
{
    public bool Equals(Item I1, Item I2)
    {
        if (I2 == null && I1 == null)
            return true;
        else if (I1 == null || I2 == null)
            return false;
        else return I1.name == I2.name && I1.price == I2.price;
    }

    public int GetHashCode(Item item)
    {
        return (item.name?.GetHashCode() ?? 0) ^ item.price.GetHashCode();
    }
}

public class Basket
{
    public Item[] items;
}

【讨论】:

    【解决方案2】:

    你可以使用Except,然后检查返回值是否有:

    // first list
    var list1 = new List<string>();
    list1.Add("A");
    list1.Add("B");
    list1.Add("C");
    list1.Add("D");
    
    // second list
    var list2 = new List<string>();
    list2.Add("C");
    list2.Add("D");
    
    var list3 = list1.Except(list2);
    var listIsIdentical = !list3.Any();
    

    【讨论】:

    • 抱歉列表必须包含引用类型 Object
    【解决方案3】:

    您需要覆盖从基类 Object 继承的默认 Equals 和 GetHashCode 方法。然后你就可以用!basket1.items.Except(basket2.items).Any();正确比较两个篮子了。

    【讨论】:

      猜你喜欢
      • 2012-10-03
      • 1970-01-01
      • 2010-09-08
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 2018-10-13
      • 2015-02-02
      • 2018-11-20
      相关资源
      最近更新 更多