使用C#编写代码,比较两个字典:
- 键为
string
类型 - 值为一个
int
列表。
当两个字典满足以下条件时,我认为它们相等:
- 它们具有相同的键
- 并且对于每个键,整数列表中的每个值都相同(不一定按照相同顺序)。
我尝试了这个和这个与之相关的问题的解决方案,但它们都未通过我的测试函数DoesOrderKeysMatter
和DoesOrderValuesMatter
的测试套件。
我的测试套件:
public static List<int> GetList(int x, int y)
{
List<int> list = new List<int>();
list.Add(x);
list.Add(y);
return list;
}
public static Dictionary<string, List<int>> GetDict1()
{
Dictionary<string, List<int>> dict1 = new Dictionary<string, List<int>>();
dict1.Add("a", GetList(1,2));
dict1.Add("b", GetList(3,4));
return dict1;
}
public static Dictionary<string, List<int>> GetDict2()
{
Dictionary<string, List<int>> dict2 = new Dictionary<string, List<int>>();
dict2.Add("b", GetList(3,4));
dict2.Add("a", GetList(1,2));
return dict2;
}
测试类。using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;
namespace UnitTestProject1
{
[TestClass]
public class ProvideReportTests
{
[TestMethod]
public void AreSameDictionariesEqual()
{
// arrange
Dictionary<string, List<int>> dict1 = GetDict1();
// act
bool dictsAreEqual = false;
dictsAreEqual = AreDictionariesEqual(dict1, dict1);
// assert
Assert.IsTrue(dictsAreEqual, "Dictionaries are not equal");
}
[TestMethod]
public void AreDifferentDictionariesNotEqual()
{
// arrange
Dictionary<string, List<int>> dict1 = GetDict1();
Dictionary<string, List<int>> dict2 = new Dictionary<string, List<int>>();
// act
bool dictsAreEqual = true;
dictsAreEqual = AreDictionariesEqual(dict1, dict2);
// assert
Assert.IsFalse(dictsAreEqual, "Dictionaries are equal");
}
[TestMethod]
public void DoesOrderKeysMatter()
{
// arrange
Dictionary<string, List<int>> dict1 = GetDict1();
Dictionary<string, List<int>> dict2 = GetDict2();
// act
bool dictsAreEqual = false;
dictsAreEqual = AreDictionariesEqual(dict1, dict2);
// assert
Assert.IsTrue(dictsAreEqual, "Dictionaries are not equal");
}
[TestMethod]
public void DoesOrderValuesMatter()
{
// arrange
Dictionary<string, List<int>> dict1 = GetDict1();
Dictionary<string, List<int>> dict2 = new Dictionary<string, List<int>>();
dict2.Add("a", GetList(2,1));
dict2.Add("b", GetList(3,4));
// act
bool dictsAreEqual = false;
dictsAreEqual = AreDictionariesEqual(dict1, dict2);
// assert
Assert.IsTrue(dictsAreEqual, "Dictionaries are not equal");
}
private bool AreDictionariesEqual(Dictionary<string, List<int>> dict1, Dictionary<string, List<int>> dict2)
{
return dict1.Keys.Count == dict2.Keys.Count &&
dict1.Keys.All(k => dict2.ContainsKey(k) &&
object.Equals(dict2[k], dict1[k]));
// also fails:
// return dict1.OrderBy(kvp => kvp.Key).SequenceEqual(dict2.OrderBy(kvp => kvp.Key));
}
}
}
这些字典的正确比较方式是什么?或者我的TestSuite(虽然笨拙地编写)中有错误吗?
更新
我正试图将Servy的答案纳入我的测试套件,如下所示,但我遇到了一些错误(在Visual Studio中用红色波浪线标出):
- 在“Equals”方法中的“SetEquals”说:“不包含接受Generic.List类型的第一个参数的定义。
- 在AreDictionariesEqual中,“DictionaryComparer”是一种类型,但被用作变量。namespace UnitTestProject1
{
[TestClass]
public class ProvideReportTests
{
[TestMethod]
// ... same as above
private bool AreDictionariesEqual(Dictionary<string, List<int>> dict1, Dictionary<string, List<int>> dict2)
{
DictionaryComparer<string, List<int>>(new ListComparer<int>() dc = new DictionaryComparer<string, List<int>>(new ListComparer<int>();
return dc.Equals(dict1, dict2);
}
}
public class DictionaryComparer<TKey, TValue> :
IEqualityComparer<Dictionary<TKey, TValue>>
{
private IEqualityComparer<TValue> valueComparer;
public DictionaryComparer(IEqualityComparer<TValue> valueComparer = null)
{
this.valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
public bool Equals(Dictionary<TKey, TValue> x, Dictionary<TKey, TValue> y)
{
if (x.Count != y.Count)
return false;
if (x.Keys.Except(y.Keys).Any())
return false;
if (y.Keys.Except(x.Keys).Any())
return false;
foreach (var pair in x)
if (!valueComparer.Equals(pair.Value, y[pair.Key]))
return false;
return true;
}
public int GetHashCode(Dictionary<TKey, TValue> obj)
{
throw new NotImplementedException();
}
}
public class ListComparer<T> : IEqualityComparer<List<T>>
{
private IEqualityComparer<T> valueComparer;
public ListComparer(IEqualityComparer<T> valueComparer = null)
{
this.valueComparer = valueComparer ?? EqualityComparer<T>.Default;
}
public bool Equals(List<T> x, List<T> y)
{
return x.SetEquals(y, valueComparer);
}
public int GetHashCode(List<T> obj)
{
throw new NotImplementedException();
}
}
public static bool SetEquals<T>(this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer)
{
return new HashSet<T>(second, comparer ?? EqualityComparer<T>.Default)
.SetEquals(first);
}
}
object.Equals(dict2[k], dict1[k])
通过引用比较列表。不同的列表实例具有不同的引用。列表中有什么项并不重要。 - Sergey BerezovskiyAreDictionariesEqual
可能需要使用Enumerable.SequenceEqual
。 - AakashMCollectionAssert.AreEquivalent
。 - AakashM