Как сделать сравнение значений между двумя словарямиобъекты - PullRequest
5 голосов
/ 14 декабря 2011

У меня есть следующая структура данных:

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 хорош здесь ..

Спасибо

Ответы [ 3 ]

4 голосов
/ 14 декабря 2011

Первый ярлык на быстрых истинах и ложных значениях:

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(), который будетпозвоните в.

Мы могли бы создать IEqualityComparer<KeyValuePair<string, List<string>>>, если бы мы были одержимы использованием SequenceEqual, но, вероятно, проще сделать подход без использования 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 голос
/ 14 декабря 2011

Я не думаю, что есть встроенный метод, но вы можете сравнить значения списка в каждой записи словаря. Примерно так:

// 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 словаря <строка, строка> Экземпляры и здесь: Есть ли встроенный метод для сравнения коллекций в C #?

0 голосов
/ 14 декабря 2011

Если вы используете NUnit, вы можете использовать CollectionAssert.AreEquivalent , см. Этот вопрос: NUnit: Dictionary Assert

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...