Есть ли встроенный метод сравнения коллекций в С#?

Я хотел бы сравнить содержимое нескольких коллекций в моем методе Equals. У меня есть словарь и IList. Есть ли встроенный метод для этого?

Отредактировано: Я хочу сравнить два словаря и два ILists, поэтому я думаю, что означает равенство, - если два словаря содержат одни и те же ключи, сопоставленные с одинаковыми значениями, то они равны.

Ответы

Ответ 1

Enumerable.SequenceEqual

Определяет, равны ли две последовательности, сравнивая их элементы, используя указанный IEqualityComparer (T).

Вы не можете напрямую сравнивать список и словарь, но вы можете сравнить список значений из Словаря со списком

Ответ 2

Как другие предложили и отметили, 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))

Ответ 3

В дополнение к упомянутому SequenceEqual, который

истинно, если два списка имеют одинаковую длину и соответствующие им элементы сравниваются равными по сравнению с компаратором

(который может быть стандартным компаратором, то есть переопределением Equals())

стоит упомянуть, что в .Net4 есть SetEquals на объектах ISet который

игнорирует порядок элементов и любые повторяющиеся элементы.

Итак, если вы хотите иметь список объектов, но им не нужно быть в определенном порядке, считайте, что правильный выбор ISet (например, HashSet).

Ответ 4

Взгляните на метод 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);

Ответ 5

.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

Ответ 6

Я не знал о методе 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 построила функцию, которую я описал для вас.

Ответ 7

Это напрямую не отвечает на ваши вопросы, но как MS TestTools, так и NUnit предоставляют

 CollectionAssert.AreEquivalent

который делает в значительной степени то, что вы хотите.

Ответ 8

Для сравнения коллекций вы также можете использовать LINQ. Enumerable.Intersect возвращает все пары, которые равны. Вы можете сравнить два словаря следующим образом:

(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count

Первое сравнение необходимо, потому что dict2 может содержать все ключи от dict1 и более.

Вы также можете использовать размышления об изменениях, используя Enumerable.Except и Enumerable.Union, что приводит к аналогичным результатам. Но можно использовать для определения точных различий между наборами.

Ответ 9

Как насчет этого примера:

 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

Ответ 11

Нет. В рамках коллекции нет понятия равенства. Если вы думаете об этом, нет никакого способа сравнить коллекции, которые не являются субъективными. Например, сравнивая ваш IList с вашим Словарем, будут ли они равны, если все ключи были в IList, все значения были в IList или если оба были в IList? Нет очевидного способа сравнения этих двух коллекций без знания того, что они должны использовать, поэтому метод равных значений общего назначения не имеет смысла.

Ответ 12

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