Есть ли встроенный метод для сравнения коллекций? - PullRequest
164 голосов
/ 04 сентября 2008

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

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

Ответы [ 14 ]

169 голосов
/ 04 сентября 2008

Enumerable.SequenceEqual

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

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

39 голосов
/ 11 января 2011

Как предлагали и отмечали другие, SequenceEqual чувствителен к порядку. Чтобы решить эту проблему, вы можете отсортировать словарь по ключу (который уникален и, следовательно, сортировка всегда стабильна), а затем использовать SequenceEqual. Следующее выражение проверяет, равны ли два словаря независимо от их внутреннего порядка:

dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))

РЕДАКТИРОВАТЬ: Как указал Джепп Стиг Нильсен, некоторые объекты имеют IComparer<T>, который несовместим с их IEqualityComparer<T>, что приводит к неверным результатам. При использовании ключей с таким объектом вы должны указать правильный IComparer<T> для этих ключей. Например, со строковыми ключами (которые демонстрируют эту проблему) вы должны сделать следующее, чтобы получить правильные результаты:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
13 голосов
/ 19 февраля 2012

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

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

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

Стоит отметить, что в .Net4 есть SetEquals для ISet объектов, который

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

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

7 голосов
/ 04 сентября 2008

Взгляните на 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 голосов
/ 30 апреля 2010

.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
4 голосов
/ 18 сентября 2012

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

 CollectionAssert.AreEquivalent

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

4 голосов
/ 04 сентября 2008

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

1 голос
/ 18 августа 2018

Для упорядоченных коллекций (List, Array) используйте SequenceEqual

для использования HashSet SetEquals

для словаря вы можете сделать:

namespace System.Collections.Generic {
  public static class ExtensionMethods {
    public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
      if (object.ReferenceEquals(d1, d2)) return true; 
      if (d2 is null || d1.Count != d2.Count) return false;
      foreach (var (d1key, d1value) in d1) {
        if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
        if (!d1value.Equals(d2value)) return false;
      }
      return true;
    }
  }
}

(более оптимизированное решение будет использовать сортировку, но для этого потребуется IComparable<TValue>)

1 голос
/ 11 апреля 2017

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

 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

1 голос
/ 27 сентября 2016

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

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

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

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

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