Я думал, что принятый ответ будет правильным, основываясь на том, что я читал в смарт-справке для метода Except: «Создает разность наборов двух последовательностей с помощью средства сравнения по умолчанию для сравнения значений». Но я обнаружил, что это не очень хороший ответ.
Рассмотрим этот код:
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]]
Как видите, настройки "oldDict" и "newDict" абсолютно одинаковы. И ни предлагаемое решение, ни вызов SequenceEqual не работают должным образом. Интересно, является ли это результатом того, что Except использует ленивую загрузку или способ, которым компаратор настроен для словаря. (Хотя, глядя на структуру и справочные объяснения, можно предположить, что).
Вот решение, которое я придумал. Обратите внимание, что я использовал следующее правило: два словаря равны, если оба содержат одинаковые ключи и значения для каждого ключа совпадают. И ключи, и значения должны быть в одинаковом последовательном порядке. И моё решение может быть не самым эффективным, так как оно основано на повторении всего набора ключей.
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"}}};