比较引用类型对象的集合是不是相等,忽略集合中项目的顺序

Posted

技术标签:

【中文标题】比较引用类型对象的集合是不是相等,忽略集合中项目的顺序【英文标题】: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(它们相等)。我应该如何进行?

【问题讨论】:

这能回答你的问题吗? Is there any way to compare two lists in C# 如果顺序无关紧要,请使用HashSet<T> 【参考方案1】:

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

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

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

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

请参阅:Except overload documentation 和 IEqualityComparer 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();正确比较两个篮子了。

【讨论】:

以上是关于比较引用类型对象的集合是不是相等,忽略集合中项目的顺序的主要内容,如果未能解决你的问题,请参考以下文章

Java面试题目集合

比较具有不同项目类型的集合

集合的概念及应用和HashSet保证数据不重复的原理

比较两个集合的相等性,而不考虑其中项目的顺序

Object Equals && GetHashCode

Java知识复习