比较引用类型对象的集合是否相等,忽略集合中项目的顺序
Comparing a collection of reference type objects for equality ignoring order of items in collection
我有以下样本类
public class Item
{
public string name { get; set; }
public double price { get; set; }
}
public class Basket
{
public Item[] items;
}
然后我做了两个 Basket
的实例,都包含 Item
s
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 }
}
};
我想比较 Basket1
和 Basket2
,忽略购物篮中物品的顺序。这个例子应该return True
(他们是相等的)比较的时候。我该如何进行?
您可以使用 Except
,然后检查 return 值中是否有任何内容:
// 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();
@Neil 的回答是正确的,除了它不适用于引用类型(字符串是一个例外,因为它们是不可变的)。
Item
是一个 class 所以它是一个引用类型。
Except
使用默认的相等比较器来比较元素。由于 Item 是一个 class,它会通过引用进行比较,这不是想要的解决方案。所以我们需要绕过默认比较,使用自定义相等比较器。为此存在 Except
的重载。
您将需要创建一个实现 IEqualityComparer<Item>
的类型并将该类型的实例传递给 Except
。
参见:Except overload documentation and IEqualityComparer documentation
这是您可以在 Linqpad 中 运行 的示例。它同时使用 Except
重载。一个returnfalse
,另一个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;
}
您需要覆盖从基础 class 对象继承的默认 Equals 和 GetHashCode 方法。然后你可以用 !basket1.items.Except(basket2.items).Any();
.
正确比较两个篮子
我有以下样本类
public class Item
{
public string name { get; set; }
public double price { get; set; }
}
public class Basket
{
public Item[] items;
}
然后我做了两个 Basket
的实例,都包含 Item
s
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 }
}
};
我想比较 Basket1
和 Basket2
,忽略购物篮中物品的顺序。这个例子应该return True
(他们是相等的)比较的时候。我该如何进行?
您可以使用 Except
,然后检查 return 值中是否有任何内容:
// 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();
@Neil 的回答是正确的,除了它不适用于引用类型(字符串是一个例外,因为它们是不可变的)。
Item
是一个 class 所以它是一个引用类型。
Except
使用默认的相等比较器来比较元素。由于 Item 是一个 class,它会通过引用进行比较,这不是想要的解决方案。所以我们需要绕过默认比较,使用自定义相等比较器。为此存在 Except
的重载。
您将需要创建一个实现 IEqualityComparer<Item>
的类型并将该类型的实例传递给 Except
。
参见:Except overload documentation and IEqualityComparer documentation
这是您可以在 Linqpad 中 运行 的示例。它同时使用 Except
重载。一个returnfalse
,另一个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;
}
您需要覆盖从基础 class 对象继承的默认 Equals 和 GetHashCode 方法。然后你可以用 !basket1.items.Except(basket2.items).Any();
.