Ответ 1
Определяет, равны ли две последовательности, сравнивая их элементы, используя указанный IEqualityComparer (T).
Вы не можете напрямую сравнивать список и словарь, но вы можете сравнить список значений из Словаря со списком
Я хотел бы сравнить содержимое нескольких коллекций в моем методе Equals. У меня есть словарь и IList. Есть ли встроенный метод для этого?
Отредактировано: Я хочу сравнить два словаря и два ILists, поэтому я думаю, что означает равенство, - если два словаря содержат одни и те же ключи, сопоставленные с одинаковыми значениями, то они равны.
Определяет, равны ли две последовательности, сравнивая их элементы, используя указанный IEqualityComparer (T).
Вы не можете напрямую сравнивать список и словарь, но вы можете сравнить список значений из Словаря со списком
Как другие предложили и отметили, SequenceEqual
чувствителен к порядку. Чтобы решить эту проблему, вы можете отсортировать словарь по ключу (который уникален, и, следовательно, сортировка всегда стабильная), а затем используйте SequenceEqual
. Следующее выражение проверяет, равны ли два словаря независимо от их внутреннего порядка:
dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
EDIT: Как отметил Джеппе Стиг Нильсен, у какого-то объекта есть IComparer<T>
, который несовместим с их IEqualityComparer<T>
, что дает неверные результаты. При использовании ключей с таким объектом вы должны указать правильный IComparer<T>
для этих ключей. Например, со строковыми ключами (которые показывают эту проблему), вы должны сделать следующее, чтобы получить правильные результаты:
dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
В дополнение к упомянутому SequenceEqual, который
истинно, если два списка имеют одинаковую длину и соответствующие им элементы сравниваются равными по сравнению с компаратором
(который может быть стандартным компаратором, то есть переопределением Equals()
)
стоит упомянуть, что в .Net4 есть SetEquals на объектах ISet
который
игнорирует порядок элементов и любые повторяющиеся элементы.
Итак, если вы хотите иметь список объектов, но им не нужно быть в определенном порядке, считайте, что правильный выбор ISet
(например, HashSet
).
Взгляните на метод Enumerable.SequenceEqual
var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);
.NET Не хватает мощных инструментов для сравнения коллекций. Я разработал простое решение, которое вы можете найти по ссылке ниже:
http://robertbouillon.com/2010/04/29/comparing-collections-in-net/
Это будет выполнять сравнение равенства независимо от порядка:
var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;
Это проверит, были ли добавлены/удалены элементы:
var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added; //Sally
var inbothlists = diff.Equal; //Bob
Это увидит, какие элементы в словаре изменились:
var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa
Я не знал о методе Enumerable.SequenceEqual(вы узнаете что-то каждый день....), но я собирался предложить использовать метод расширения; что-то вроде этого:
public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
{
if (InternalList.Count != ExternalList.Count)
{
return false;
}
else
{
for (int i = 0; i < InternalList.Count; i++)
{
if (InternalList[i] != ExternalList[i])
return false;
}
}
return true;
}
Интересно, что после того, как 2 секунды прочитал о SequenceEqual, похоже, что Microsoft построила функцию, которую я описал для вас.
Это напрямую не отвечает на ваши вопросы, но как MS TestTools, так и NUnit предоставляют
CollectionAssert.AreEquivalent
который делает в значительной степени то, что вы хотите.
Для сравнения коллекций вы также можете использовать LINQ. Enumerable.Intersect
возвращает все пары, которые равны. Вы можете сравнить два словаря следующим образом:
(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count
Первое сравнение необходимо, потому что dict2
может содержать все ключи от dict1
и более.
Вы также можете использовать размышления об изменениях, используя Enumerable.Except
и Enumerable.Union
, что приводит к аналогичным результатам. Но можно использовать для определения точных различий между наборами.
Как насчет этого примера:
static void Main()
{
// Create a dictionary and add several elements to it.
var dict = new Dictionary<string, int>();
dict.Add("cat", 2);
dict.Add("dog", 3);
dict.Add("x", 4);
// Create another dictionary.
var dict2 = new Dictionary<string, int>();
dict2.Add("cat", 2);
dict2.Add("dog", 3);
dict2.Add("x", 4);
// Test for equality.
bool equal = false;
if (dict.Count == dict2.Count) // Require equal count.
{
equal = true;
foreach (var pair in dict)
{
int value;
if (dict2.TryGetValue(pair.Key, out value))
{
// Require value be equal.
if (value != pair.Value)
{
equal = false;
break;
}
}
else
{
// Require key be present.
equal = false;
break;
}
}
}
Console.WriteLine(equal);
}
Предоставлено: https://www.dotnetperls.com/dictionary-equals
Нет, поскольку структура не знает, как сравнить содержимое ваших списков.
Посмотрите на это:
http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx
Нет. В рамках коллекции нет понятия равенства. Если вы думаете об этом, нет никакого способа сравнить коллекции, которые не являются субъективными. Например, сравнивая ваш IList с вашим Словарем, будут ли они равны, если все ключи были в IList, все значения были в IList или если оба были в IList? Нет очевидного способа сравнения этих двух коллекций без знания того, что они должны использовать, поэтому метод равных значений общего назначения не имеет смысла.
public bool CompareStringLists(List<string> list1, List<string> list2)
{
if (list1.Count != list2.Count) return false;
foreach(string item in list1)
{
if (!list2.Contains(item)) return false;
}
return true;
}