假设字典键和值的equals和hash方法正确实现,那么测试两个字典相等的最简洁有效的方法是什么?
在这种情况下,如果它们包含相同的一组键(顺序并不重要),则说两个词典是相同的。对于每个这样的键,它们都同意该值。
这里有一些我提出的方法(可能还有更多):
public bool Compare1<TKey, TValue>(
Dictionary<TKey, TValue> dic1,
Dictionary<TKey,TValue> dic2)
{
return dic1.OrderBy(x => x.Key).
SequenceEqual(dic2.OrderBy(x => x.Key));
}
public bool Compare2<TKey, TValue>(
Dictionary<TKey, TValue> dic1,
Dictionary<TKey, TValue> dic2)
{
return (dic1.Count == dic2.Count &&
dic1.Intersect(dic2).Count().
Equals(dic1.Count));
}
public bool Compare3<TKey, TValue>(
Dictionary<TKey, TValue> dic1,
Dictionary<TKey, TValue> dic2)
{
return (dic1.Intersect(dic2).Count().
Equals(dic1.Union(dic2).Count()));
}
答案 0 :(得分:91)
dic1.Count == dic2.Count && !dic1.Except(dic2).Any();
答案 1 :(得分:12)
这实际上取决于平等意味着什么。
此方法将测试两个字典包含具有相同值的相同键(假设两个字典都使用相同的IEqualityComparer<TKey>
实现)。
public bool CompareX<TKey, TValue>(
Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2)
{
if (dict1 == dict2) return true;
if ((dict1 == null) || (dict2 == null)) return false;
if (dict1.Count != dict2.Count) return false;
var valueComparer = EqualityComparer<TValue>.Default;
foreach (var kvp in dict1)
{
TValue value2;
if (!dict2.TryGetValue(kvp.Key, out value2)) return false;
if (!valueComparer.Equals(kvp.Value, value2)) return false;
}
return true;
}
答案 2 :(得分:3)
您可以使用linq进行键/值比较:
public bool Compare<TKey, TValue>(Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue dict2)
{
IEqualityComparer<TValue> valueComparer = EqualityComparer<TValue>.Default;
return dict1.Count == dict2.Count &&
dict1.Keys.All(key => dict2.ContainsKey(key) && valueComparer.Equals(dict1[key], dict2[key]));
}
答案 3 :(得分:1)
bool equals = a.Intersect(b).Count() == a.Union(b).Count()
是关于数组的,但就使用IEnumerable<T>
方法而言,它也可以用于Dictionary<K,V>
。
答案 4 :(得分:1)
我认为接受的答案是正确的,基于我在smarthelp中为Except方法阅读的内容:&#34;通过使用默认的相等比较器来比较值来产生两个序列的集合差异。&#34;但我发现这不是一个好的答案。
考虑以下代码:
Dictionary<string, List<string>> oldDict = new Dictionary<string, List<string>>()
{{"001A", new List<string> {"John", "Doe"}},
{"002B", new List<string> {"Frank", "Abignale"}},
{"003C", new List<string> {"Doe", "Jane"}}};
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>()
{{"001A", new List<string> {"John", "Doe"}},
{"002B", new List<string> {"Frank", "Abignale"}},
{"003C", new List<string> {"Doe", "Jane"}}};
bool equal = oldDict.Count.Equals(newDict.Count) && !oldDict.Except(newDict).Any();
Console.WriteLine(string.Format("oldDict {0} newDict", equal?"equals":"does not equal"));
equal = oldDict.SequenceEqual(newDict);
Console.WriteLine(string.Format("oldDict {0} newDict", equal ? "equals" : "does not equal"));
Console.WriteLine(string.Format("[{0}]", string.Join(", ",
oldDict.Except(newDict).Select(k =>
string.Format("{0}=[{1}]", k.Key, string.Join(", ", k.Value))))));
这导致以下结果:
oldDict does not equal newDict
oldDict does not equal newDict
[001A=[John, Doe], 002B=[Frank, Abignale], 003C=[Doe, Jane]]
正如你所看到的,&#34; oldDict&#34;和&#34; newDict&#34;设置完全相同。并且建议的解决方案和对SequenceEqual的调用都不能正常工作。我想知道它是否是Except使用延迟加载或者为Dictionary设置比较器的方式的结果。 (虽然,查看结构和参考解释表明它应该。)
这是我提出的解决方案。请注意,我使用的规则如下:如果两个字典包含相同的键并且每个键的值匹配,则两个字典相等。键和值必须按相同的顺序排列。我的解决方案可能不是最有效的,因为它依赖于遍历整个键集。
private static bool DictionaryEqual(
Dictionary<string, List<string>> oldDict,
Dictionary<string, List<string>> newDict)
{
// Simple check, are the counts the same?
if (!oldDict.Count.Equals(newDict.Count)) return false;
// Verify the keys
if (!oldDict.Keys.SequenceEqual(newDict.Keys)) return false;
// Verify the values for each key
foreach (string key in oldDict.Keys)
if (!oldDict[key].SequenceEqual(newDict[key]))
return false;
return true;
}
如果出现以下情况,请查看结果如何变化: 关键顺序不一样。 (返回false)
newDict = new Dictionary<string, List<string>>()
{{"001A", new List<string> {"John", "Doe"}},
{"003C", new List<string> {"Doe", "Jane"}},
{"002B", new List<string> {"Frank", "Abignale"}}};
和 键顺序匹配,但值不匹配(返回false)
newDict = new Dictionary<string, List<string>>()
{{"001A", new List<string> {"John", "Doe"}},
{"002B", new List<string> {"Frank", "Abignale"}},
{"003C", new List<string> {"Jane", "Doe"}}};
如果序列顺序无关紧要,可以将函数更改为以下内容,但可能会影响性能。
private static bool DictionaryEqual_NoSort(
Dictionary<string, List<string>> oldDict,
Dictionary<string, List<string>> newDict)
{
// Simple check, are the counts the same?
if (!oldDict.Count.Equals(newDict.Count)) return false;
// iterate through all the keys in oldDict and
// verify whether the key exists in the newDict
foreach(string key in oldDict.Keys)
{
if (newDict.Keys.Contains(key))
{
// iterate through each value for the current key in oldDict and
// verify whether or not it exists for the current key in the newDict
foreach(string value in oldDict[key])
if (!newDict[key].Contains(value)) return false;
}
else { return false; }
}
return true;
}
检查DictionaryEqual_NoSort是否使用以下newDict(DictionaryEquals_NoSort返回true):
newDict = new Dictionary<string, List<string>>()
{{"001A", new List<string> {"John", "Doe"}},
{"003C", new List<string> {"Jane", "Doe"}},
{"002B", new List<string> {"Frank", "Abignale"}}};
答案 5 :(得分:1)
除了@Nick Jones答案之外,您还需要以与顺序无关的相同方式来实现gethashcode。我建议像这样:
public override int GetHashCode()
{
int hash = 13;
var orderedKVPList = this.DictProp.OrderBy(kvp => kvp.key)
foreach (var kvp in orderedKVPList)
{
hash = (hash * 7) + kvp.Key.GetHashCode();
hash = (hash * 7) + kvp.value.GetHashCode();
}
return hash;
}
答案 6 :(得分:0)
如果两个词典包含相同的键,但顺序不同,它们是否应该被认为是相同的?如果没有,那么应该通过同时运行枚举器来比较字典。这可能比通过一个字典枚举并查找另一个字典中的每个元素更快。如果你已经知道相同的词典将以相同的顺序排列它们的元素,那么这种双重枚举可能是要走的路。
答案 7 :(得分:0)
在OP问题中它确实说同等性测试不仅要涵盖密钥的匹配,还要涵盖它们的值“在这种情况下,如果它们包含相同的密钥集,则说两个字典相等(顺序)并不重要),对于每一个这样的密钥,他们都同意价值。“
我是否遗漏了某些内容或标记的答案https://stackoverflow.com/a/3804852/916121仅检查尺寸和按键是否相等而不是它们的值?
我会在答案旁边发布这个但是无法解决如何将其添加为评论,抱歉。
答案 8 :(得分:0)
对于嵌套字典和列表,我在此处结合了以下几个想法:https://gist.github.com/NullVoxPopuli/f95baaa48b4e9854dcfe(此处发布的代码太多)~100行