如何在两个Dictionary>对象

本文关键字:string List 对象 Dictionary 两个 | 更新日期: 2023-09-27 18:17:43

我有以下数据结构:

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在这里是好的。

谢谢

如何在两个Dictionary<string, List<string>>对象

快速判断真假的第一个快捷键:

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也将在其他地方使用时,它才真正简洁。

我不认为有内置的方法,但您可以比较每个字典条目中的列表值。像这样:

// 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;

看这里:比较2 Dictionary<string,>实例和这里:c#中是否有一个内置的方法来比较集合?

如果你正在使用NUnit,你可以使用CollectionAssert。NUnit: Dictionary Assert