¿Hay un método incorporado para comparar colecciones?


Me gustaría comparar el contenido de un par de colecciones en mi método Equals. Tengo un Diccionario y un IList. ¿Hay un método incorporado para hacer esto?

Editado: Quiero comparar dos Diccionarios y dos ilistas, así que creo que lo que significa igualdad es claro-si los dos diccionarios contienen las mismas claves asignadas a los mismos valores, entonces son iguales.

Author: Uwe Keim, 2008-09-04

14 answers

Enumerable.SequenceEqual

Determina si dos secuencias son iguales comparando sus elementos usando un IEqualityComparer(T) especificado.

No puede comparar directamente la lista y el diccionario, pero puede comparar la lista de valores del Diccionario con la lista

 159
Author: Glenn Slaven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-16 17:53:17

Como otros han sugerido y han señalado, SequenceEqual es sensible al orden. Para resolver eso, puede ordenar el diccionario por clave (que es única, y por lo tanto la ordenación es siempre estable) y luego usar SequenceEqual. La siguiente expresión comprueba si dos diccionarios son iguales independientemente de su orden interno:

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

EDIT: Como señaló Jeppe Stig Nielsen, algunos objetos tienen un IComparer<T> que es incompatible con su IEqualityComparer<T>, dando resultados incorrectos. Cuando se utilizan claves con un objeto, debe especificar un IComparer<T> correcto para esas claves. Por ejemplo, con las teclas de cadena (que muestran este problema), debe hacer lo siguiente para obtener resultados correctos:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
 36
Author: Allon Guralnek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-14 09:57:24

Además de la secuencia mencionada igual , que

Es verdadero si dos listas son de igual longitud y su correspondiente los elementos comparan igual según un comparador

(que puede ser el comparador predeterminado, es decir, un Equals() anulado)

Vale la pena mencionar que en. Net4 hay SetEquals en ISet objetos, que

Ignora el orden de los elementos y cualquier elemento duplicado.

Así que si quieres tenga una lista de objetos, pero no necesitan estar en un orden específico, considere que un ISet (como un HashSet) puede ser la elección correcta.

 13
Author: Desty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-19 10:58:05

Echa un vistazo a la Enumerable.SequenceEqual método

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);
 7
Author: aku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-04 11:55:20

. NET Carece de herramientas poderosas para comparar colecciones. He desarrollado una solución simple que puede encontrar en el siguiente enlace:

Http://robertbouillon.com/2010/04/29/comparing-collections-in-net /

Esto realizará una comparación de igualdad sin importar el orden:

var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;

Esto comprobará si se agregaron / eliminaron elementos:

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

Esto verá qué elementos en el diccionario cambiaron:

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
 5
Author: user329244,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-29 20:26:10

No sabía sobre Enumerable.Secuenciamétodo igual (aprendes algo todos los días....), pero yo iba a sugerir el uso de un método de extensión; algo como esto:

    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;

    }

Curiosamente, después de tomar 2 segundos para leer sobre SequenceEqual, parece que Microsoft ha construido la función que describí para usted.

 4
Author: Giovanni Galbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-04 11:31:09

Esto no responde directamente a sus preguntas, pero tanto las herramientas de prueba de MS como NUnit proporcionan

 CollectionAssert.AreEquivalent

Que hace más o menos lo que quieres.

 4
Author: tymtam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-18 03:45:49

Para comparar colecciones también puede usar LINQ. Enumerable.Intersect devuelve todos los pares que son iguales. Puedes comparar dos diccionarios como este:

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

La primera comparación es necesaria porque dict2 puede contener todas las claves de dict1 y más.

También puede utilizar pensar de variaciones con Enumerable.Except y Enumerable.Union que conducen a resultados similares. Pero se puede utilizar para determinar las diferencias exactas entre conjuntos.

 1
Author: Chrono,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-27 08:43:16

Qué tal este ejemplo:

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

Cortesía : https://www.dotnetperls.com/dictionary-equals

 1
Author: ispostback,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-11 18:19:03

No. El marco de la colección no tiene ningún concepto de igualdad. Si lo piensas, no hay forma de comparar colecciones que no sea subjetiva. Por ejemplo, comparando su IList con su Diccionario, ¿serían iguales si todas las claves estuvieran en el IList, todos los valores estuvieran en el IList o si ambos estuvieran en el IList? No hay una manera obvia de comparar estas dos colecciones sin el conocimiento de lo que van a ser utilizados para lo que un propósito general igual método no tiene sentido.

 0
Author: Evil Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-04 11:33:32

No, porque el framework no sabe cómo comparar el contenido de tus listas.

Echa un vistazo a esto:

Http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx

 0
Author: Mark Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-13 14:35:37
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;
}
 0
Author: mbadeveloper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-12 21:57:28

No hubo, no hay y podría no haber, al menos yo lo creería. La razón detrás es que la igualdad de la colección es probablemente un comportamiento definido por el usuario.

Los elementos en las colecciones no se supone que estén en un orden particular, aunque tienen un orden natural, no es en lo que deberían confiar los algoritmos de comparación. Digamos que tienes dos colecciones de:

{1, 2, 3, 4}
{4, 3, 2, 1}

Son iguales o no? Debes saberlo, pero no se cual es tu punto de vista.

Las colecciones son conceptualmente desordenado por defecto, hasta que los algoritmos proporcionan las reglas de ordenación. Lo mismo que SQL server traerá a su atención es que cuando intenta hacer paginación, requiere que proporcione reglas de clasificación:

Https://docs.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017

Otras dos colecciones:

{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}

De Nuevo, son iguales o no? Dímelo tú ..

Elemento repetibilidad de a la colección juega su papel en diferentes escenarios y algunas colecciones como Dictionary<TKey, TValue> ni siquiera permiten elementos repetidos.

Creo que estos tipos de igualdad están definidos en la aplicación y, por lo tanto, el marco no proporcionó todas las implementaciones posibles.

Bueno, en general Enumerable.SequenceEqual es suficiente pero devuelve false en el siguiente caso:

var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false

He leído algunas respuestas a preguntas como esta (usted puede google para ellos) y lo que usaría, en generalidades:

public static class CollectionExtensions {
    public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
        if(object.ReferenceEquals(first, second)) {
            return true;
        }

        if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
            return Enumerable.SequenceEqual(first, second);
        }

        if(first is ICollection<T> && second is ICollection<T>) {
            if(first.Count()!=second.Count()) {
                return false;
            }
        }

        first=first.OrderBy(x => x.GetHashCode());
        second=second.OrderBy(x => x.GetHashCode());
        return CollectionExtensions.Represents(first, second);
    }
}

Eso significa que una colección representa a la otra en sus elementos incluyendo tiempos repetidos sin tener en cuenta el orden original. Algunas notas sobre la aplicación:

  • GetHashCode() es solo para el ordenamiento no para la igualdad; creo que es suficiente en este caso

  • Count() realmente no enumera la colección y caen directamente en la implementación de propiedades de ICollection<T>.Count

  • Si las referencias son iguales, es sólo Boris

 0
Author: Ken Kin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-10 05:48:24

Para colecciones ordenadas (Lista, Matriz) use SequenceEqual

Para usar el HashSet SetEquals

Para el Diccionario puedes hacer:

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

(Una solución más optimizada utilizará la ordenación, pero eso requerirá IComparable<TValue>)

 0
Author: kofifus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-20 02:01:59