Pregunta

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 integrado para hacer esto?

Editado:Quiero comparar dos Diccionarios y dos ILists, 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.

¿Fue útil?

Solución

Enumerable.SequenceEqual

Determina si dos secuencias son iguales mediante la comparación de sus elementos mediante el uso de un determinado IEqualityComparer(T).

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

Otros consejos

Como otros han sugerido, y hemos observado, SequenceEqual es de orden sensible.Para solucionar esto, se puede ordenar el diccionario clave (que es único, y por lo tanto el orden es siempre estable) y, a continuación, utilizar 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))

EDITAR: Como se ha señalado por Jeppe Stig Nielsen, algunos objetos tienen un IComparer<T> que es incompatible con su IEqualityComparer<T>, produciendo resultados incorrectos.Cuando el uso de las teclas con un objeto, se debe especificar una correcta IComparer<T> para esas llaves.Por ejemplo, con cadena de claves (que presentan este problema), debe hacer lo siguiente con el fin de obtener resultados correctos:

dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))

Además de los mencionados SequenceEqual, que

es true si dos listas de la misma longitud y sus correspondientes elementos de comparar la igualdad de acuerdo a un comparador

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

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

ignora el orden de los elementos y cualquier elementos duplicados.

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

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

.NET Carece de potentes herramientas para la comparación de colecciones.He desarrollado una solución simple que usted puede encontrar en el siguiente enlace:

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

Se realizará una comparación de igualdad, independientemente de orden:

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

Esto comprobará si los artículos se han añadido / quitado:

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

Este se vea lo que los elementos en el diccionario cambiado:

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

Yo no sabía acerca de Enumerable.SequenceEqual método (se aprende algo cada día....), 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 2 segundos para leer acerca de SequenceEqual, parece que Microsoft ha incorporado la función que he descrito para usted.

Esto es no responder directamente a sus preguntas, pero la MS' TestTools y NUnit proporcionar

 CollectionAssert.AreEquivalent

que hace bastante más de lo que usted desea.

Para comparar colecciones también se pueden utilizar LINQ. Enumerable.Intersect devuelve todos los pares que son iguales.Usted puede comparse 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 puede ser utilizado para determinar las diferencias exactas entre conjuntos.

Cómo acerca de 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

Para colecciones ordenadas (Lista, Matriz) uso SequenceEqual

para HashSet uso SetEquals

para el Diccionario que usted puede 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;
    }
  }
}

(Más solución optimizada utilizará la clasificación, pero que se requieren IComparable<TValue>)

No.La colección de marco no tiene ningún concepto de igualdad.Si usted piensa acerca de lo que no hay forma de comparar colecciones que no es subjetiva.Por ejemplo, la comparación de su IList a su Diccionario, no iban a ser iguales, si todas las llaves que estaban en la interfaz IList, todos los valores fueron en la interfaz IList o si ambos estaban en la interfaz IList?No hay ninguna manera obvia de la comparación de estas dos colecciones, sin conocimiento de lo que son para ser utilizado para un propósito general el método equals no tiene sentido.

No, porque el marco no sabe cómo comparar el contenido de sus listas.

Eche un vistazo a esto:

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

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

No fue, no es y no puede ser, al menos yo lo creo.La razón detrás de la colección es de la igualdad es, probablemente, un usuario de comportamiento definido.

Elementos de las colecciones se supone que no deben estar en un orden particular, aunque no tienen un orden natural, no es lo que la comparación de los algoritmos deben confiar.Decir que hay dos colecciones de:

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

Son iguales o no?Usted debe saber, pero no sé cuál es tu punto de vista.

Las colecciones son conceptualmente desordenada por defecto, hasta que los algoritmos proporcionan las reglas de ordenación.Lo mismo SQL server va a traer a su atención es cuando usted tratando de hacer la paginación, se requiere que usted 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

Sin embargo, otras dos colecciones:

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

De nuevo, son iguales o no?Me dices ..

Elemento de repetibilidad de una colección juega su papel en los diferentes escenarios y algunas colecciones como Dictionary<TKey, TValue> incluso no permitir que los elementos repetidos.

Creo que este tipo de igualdad son definidos por la aplicación y el marco, por tanto, no proporcionan todas las posibles implementaciones.

Bueno, en general los casos Enumerable.SequenceEqual es bastante bueno pero se devuelve el valor false en el caso siguiente:

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(puede google para ellos) y lo que me gustaría utilizar, en general:

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 la otra en sus elementos, como repetidas veces sin tener el original de pedidos en cuenta.Algunas notas de la aplicación:

  • GetHashCode() es sólo para los pedidos no por la igualdad;Creo que es suficiente en este caso

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

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top