我想在我的Equals方法中比较几个集合的内容。我有一个词典和一个IList。有没有内置的方法来做到这一点?
编辑: 我想比较两个字典和两个IList,所以我认为平等意味着什么 - 如果两个字典包含映射到相同值的相同键,那么它们是相等的。
答案 0 :(得分:169)
通过使用指定的IEqualityComparer(T)比较它们的元素来确定两个序列是否相等。
您无法直接比较列表&字典,但您可以将字典中的值列表与列表进行比较
答案 1 :(得分:39)
正如其他人所建议并注意到的那样,SequenceEqual
对订单敏感。要解决这个问题,您可以按键对字典进行排序(这是唯一的,因此排序始终是稳定的),然后使用SequenceEqual
。以下表达式检查两个字典是否相等,无论其内部顺序如何:
dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
编辑:正如Jeppe Stig Nielsen所指出的,某个对象的IComparer<T>
与IEqualityComparer<T>
不兼容,导致结果不正确。使用具有此类对象的键时,必须为这些键指定正确的IComparer<T>
。例如,使用字符串键(显示此问题),您必须执行以下操作才能获得正确的结果:
dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
答案 2 :(得分:13)
除了上面提到的SequenceEqual,
如果两个列表的长度相等且相应,则为真 元素根据比较器进行比较
(可能是默认的比较器,即覆盖Equals()
)
值得一提的是.Net4在ISet
个对象上有SetEquals个,
这
忽略元素和任何重复元素的顺序。
因此,如果您想要一个对象列表,但它们不需要按特定顺序排列,请考虑ISet
(如HashSet
)可能是正确的选择。
答案 3 :(得分:7)
var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);
答案 4 :(得分:5)
.NET缺少用于比较集合的强大工具。我开发了一个简单的解决方案,您可以在以下链接中找到:
http://robertbouillon.com/2010/04/29/comparing-collections-in-net/
无论顺序如何,这都将执行相等比较:
var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;
这将检查项目是否已添加/删除:
var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added; //Sally
var inbothlists = diff.Equal; //Bob
这将看到字典中的哪些项目发生了变化:
var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa
答案 5 :(得分:4)
我不知道Enumerable.SequenceEqual方法(你每天都学到东西......),但我打算建议使用扩展方法;像这样的东西:
public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
{
if (InternalList.Count != ExternalList.Count)
{
return false;
}
else
{
for (int i = 0; i < InternalList.Count; i++)
{
if (InternalList[i] != ExternalList[i])
return false;
}
}
return true;
}
有趣的是,在花了2秒钟阅读有关SequenceEqual之后,看起来微软已经构建了我为你描述的功能。
答案 6 :(得分:4)
这不是直接回答你的问题,而是MS'TestTools和NUnit提供
CollectionAssert.AreEquivalent
几乎可以满足您的需求。
答案 7 :(得分:1)
要比较集合,您还可以使用LINQ。 Enumerable.Intersect
返回所有相等的对。你可以像这样比较两个词典:
(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count
需要进行第一次比较,因为dict2
可以包含来自dict1
的所有密钥以及更多内容。
您还可以使用Enumerable.Except
和Enumerable.Union
来考虑导致类似结果的变体。但可用于确定集合之间的确切差异。
答案 8 :(得分:1)
这个例子怎么样:
static void Main()
{
// Create a dictionary and add several elements to it.
var dict = new Dictionary<string, int>();
dict.Add("cat", 2);
dict.Add("dog", 3);
dict.Add("x", 4);
// Create another dictionary.
var dict2 = new Dictionary<string, int>();
dict2.Add("cat", 2);
dict2.Add("dog", 3);
dict2.Add("x", 4);
// Test for equality.
bool equal = false;
if (dict.Count == dict2.Count) // Require equal count.
{
equal = true;
foreach (var pair in dict)
{
int value;
if (dict2.TryGetValue(pair.Key, out value))
{
// Require value be equal.
if (value != pair.Value)
{
equal = false;
break;
}
}
else
{
// Require key be present.
equal = false;
break;
}
}
}
Console.WriteLine(equal);
}
答案 9 :(得分:1)
对于有序集合(列表,数组),请使用max
对于HashSet使用SequenceEqual
对于词典,您可以执行以下操作:
SetEquals
(更优化的解决方案将使用排序,但需要namespace System.Collections.Generic {
public static class ExtensionMethods {
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
if (object.ReferenceEquals(d1, d2)) return true;
if (d2 is null || d1.Count != d2.Count) return false;
foreach (var (d1key, d1value) in d1) {
if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
if (!d1value.Equals(d2value)) return false;
}
return true;
}
}
}
)
答案 10 :(得分:0)
答案 11 :(得分:0)
没有。集合框架没有任何平等概念。如果你考虑一下,就无法比较非主观的集合。例如,将IList与Dictionary进行比较,如果所有键都在IList中,它们是否相等,所有值都在IList中,或者两者都在IList中?没有明显的方法来比较这两个集合而不知道它们将被用于什么,因此通用等于方法毫无意义。
答案 12 :(得分:0)
public bool CompareStringLists(List<string> list1, List<string> list2)
{
if (list1.Count != list2.Count) return false;
foreach(string item in list1)
{
if (!list2.Contains(item)) return false;
}
return true;
}
答案 13 :(得分:0)
没有,不是也可能不是,至少我会这么认为。背后的原因是集合相等可能是用户定义的行为。
集合中的元素不应该按特定的顺序排列,尽管它们确实有自然的排序,而不是比较算法应该依赖的元素。假设您有两个集合:
{1, 2, 3, 4}
{4, 3, 2, 1}
他们是否平等?你必须知道,但我不知道你的观点是什么。
默认情况下,集合在概念上是无序的,直到算法提供排序规则。 SQL服务器会引起你注意的是,当你尝试分页时,它需要你提供排序规则:
另外两个系列:
{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}
同样,他们是否平等?你告诉我..
集合的元素可重复性在不同场景中发挥作用,而某些集合(如Dictionary<TKey, TValue>
)甚至不允许重复元素。
我认为这些类型的相等是应用程序定义的,因此框架没有提供所有可能的实现。
嗯,一般情况下Enumerable.SequenceEqual
足够好但在下列情况下返回false:
var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false
我读了一些像这样的问题的答案(你可以google对他们来说)以及我会使用的一般问题:
public static class CollectionExtensions {
public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
if(object.ReferenceEquals(first, second)) {
return true;
}
if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
return Enumerable.SequenceEqual(first, second);
}
if(first is ICollection<T> && second is ICollection<T>) {
if(first.Count()!=second.Count()) {
return false;
}
}
first=first.OrderBy(x => x.GetHashCode());
second=second.OrderBy(x => x.GetHashCode());
return CollectionExtensions.Represents(first, second);
}
}
这意味着一个集合在其元素中表示另一个集合,包括重复次数而不考虑原始排序。实施的一些注意事项:
GetHashCode()
仅用于排序而不是平等;我认为在这种情况下就足够了
Count()
不会真正枚举该集合,而是直接属于ICollection<T>.Count
如果引用相同,那就是Boris
答案 14 :(得分:0)
我已经制定了自己的比较方法。它会返回常见,缺失和多余的值。
private static void Compare<T>(IEnumerable<T> actual, IEnumerable<T> expected, out IList<T> common, out IList<T> missing, out IList<T> extra) {
common = new List<T>();
missing = new List<T>();
extra = new List<T>();
var expected_ = new LinkedList<T>( expected );
foreach (var item in actual) {
if (expected_.Remove( item )) {
common.Add( item );
} else {
extra.Add( item );
}
}
foreach (var item in expected_) {
missing.Add( item );
}
}