我有以下数据结构:
Dictionary<string, List<string>>
如何进行比较以确保两个不同对象之间的值相等?
即:
Dictionary<string, List<string>> expected = new Dictionary<string, List<string>>();
expected.Add("CREDIT", new List<string> { "K R EH D IH T" });
expected.Add("CARD", new List<string> { "K AA R D" });
Dictionary<string, List<string>> actual;
actual = target.GetTermDictionary();
if (!Enumerable.SequenceEqual(expected, actual))
{
Assert.Fail();
}
我不认为SequanceEqual在这里很好..
由于
答案 0 :(得分:4)
快速结队和失败的第一条捷径:
if(ReferenceEqual(actual, expected))
return true;
if(actual == null || expected == null || actual.Count != expected.Count)
return false;
这也处理空值检查,因此我们不会抛出空引用异常。你可以跳过所有这个比较计数的条,如果你刚刚在你的例子中创建了它,但是如果你把它放在一个单独的方法中则应该保留它,以防万一。
我们不能只在两个词典上调用SequenceEqual,因为我们无法保证以相同的顺序返回键。我们可以使用其他类型的值:
return actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key));
但是这不起作用,因为两个序列相等的List<string>
值不会被认为等于它将调用的DefaultEqualityComparer<List<string>>.Equals()
方法。
如果我们在使用SequenceEqual时受到地狱限制,我们可以创建一个IEqualityComparer<KeyValuePair<string, List<string>>>
,但是使用非Linq方法可能更简单,即使Linq通常更简单,更简洁(一旦找到通往这样做。因此:
List<string> expectedVal;
foreach(KeyValuePair<string, List<string> kvp in actual)
{
if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal))
return false;
}
return true;
变体可以处理不同的平等观点。例如,如果我们想要考虑不同订单中相同项目的两个列表,我们可以使用kvp.Value.OrderBy(x => x).SequenceEquals(expectedVal.OrderBy(x => x))
。
总之,这个地方在一起:
if(ReferenceEqual(actual, expected))
return true;
if(actual == null || expected == null || actual.Count != expected.Count)
return false;
List<string> expectedVal;
foreach(KeyValuePair<string, List<string> kvp in actual)
{
if(!expected.TryGetValue(kvp.key, out expectedVal) || kvp.Value.Count != expectedVal.Count || !kvp.Value.SequenceEquals(expectedVal))
return false;
}
return true;
编辑:只是为了好玩,使用SequenceEquals的方式:
internal class KvpSLSEq : IEqualityComparer<KeyValuePair<string, List<string>>>
{
public bool Equals(KeyValuePair<string, List<string>> x, KeyValuePair<string, List<string>> y)
{
return x.Key == y.Key && x.Value.Count == y.Value.Count && x.Value.SequenceEquals(y.Value);
}
public int GetHashCode(KeyValuePair<string, List<string>> obj)
{
//you could just throw NotImplementedException unless you'll reuse this elsewhere.
int hash = obj.Key.GetHashCode;
foreach(string val in obj.Value)
hash = hash * 31 + (val == null ? 0 : val.GetHashCode());
}
}
这样做我们可以使用简洁:
actual.OrderBy(kvp => kvp.Key).SequenceEqual(expected.OrderBy(kvp => kvp.Key), new KvpSLSEq());
但如果KvpSLSEq也将在其他地方使用,那么它真的很简洁。
答案 1 :(得分:1)
我认为没有内置方法,但您可以比较每个词典条目中的列表值。像这样:
// Check actual doesn't contain excess keys
if (actual.Keys.Count != expected.Keys.Count)
{
return false;
}
foreach(var key in expected.Keys)
{
if (!actual.ContainsKey(key) || !actual[key].SequenceEqual(expected[key]))
{
return false;
}
}
return true;
在这里查看:Comparing 2 Dictionary<string, string> Instances和此处:Is there a built-in method to compare collections in C#?
答案 2 :(得分:0)
如果您使用的是NUnit,可以使用CollectionAssert.AreEquivalent,请参阅此问题:NUnit: Dictionary Assert