2009-05-18 7 views
18

? Hay muchas maneras de hacerlo, pero siento que me he perdido una función o algo así.¿Cuál es la mejor manera de verificar dos listas de <T> listas para la igualdad en C#

Obviamente List == List usará Object.Equals() y devolverá false.

Si cada elemento de la lista es igual y está presente en la misma ubicación en la lista opuesta, entonces los consideraría iguales. Estoy usando tipos de valor, pero un objeto Datos implementado correctamente debería funcionar de la misma manera (es decir, no estoy buscando una lista copiada poco profunda, solo que el valor de cada objeto dentro es el mismo).

He intentado buscar y hay preguntas similares, pero mi pregunta es la igualdad de cada elemento, en un orden exacto.

+1

Pregunta similar: http://stackoverflow.com/questions/308476/how-to-find-out-whether-collection-collection-contain-the-same-objects –

+0

Gracias por hacérmelo saber. – Spence

Respuesta

39
Enumerable.SequenceEqual<TSource> 

MSDN

+0

usando System.Linq; ¿Eso arrojará si las secuencias son de diferente duración o están fuera de servicio, etc.? – Spence

+0

Este método hace una pregunta, por lo que no debe proporcionar la respuesta tirando. La única razón por la que debería arrojarse es si cualquiera de las secuencias es una referencia nula. –

+0

lo siento demasiado rápido. ¿Devolverá falso si las secuencias son de diferente longitud o fuera de orden? – Spence

3

aplicación mal es

if (List1.Count == List2.Count) 
{ 
    for(int i = 0; i < List1.Count; i++) 
    { 
     if(List1[i] != List2[i]) 
     { 
     return false; 
     } 
    } 
    return true; 
} 
return false; 
+2

Esto es casi exactamente como funciona el método SequenceEqual incorporado, como en la respuesta de Leppie. (Su versión regresará ligeramente más rápido que SequenceEqual si las colecciones tienen diferentes longitudes pero está restringido a IList , mientras que SequenceEqual funcionará con cualquier IEnumerable .) – LukeH

+0

Su método implementado debe ordenar los elementos de la lista para que sean precisos –

2

Eliminé un método de extensión rápida:

namespace ExtensionMethods 
{ 
    public static class MyExtensions 
    { 
     public static bool Matches<T>(this List<T> list1, List<T> list2) 
     { 
      if (list1.Count != list2.Count) return false; 
      for (var i = 0; i < list1.Count; i++) 
      { 
       if (list1[i] != list2[i]) return false; 
      } 
      return true; 
     } 
    } 
} 
3

junté esta variación:

private bool AreEqual<T>(List<T> x, List<T> y) 
{ 
    // same list or both are null 
    if (x == y) 
    { 
     return true; 
    } 

    // one is null (but not the other) 
    if (x== null || y == null) 
    { 
     return false; 
    } 

    // count differs; they are not equal 
    if (x.Count != y.Count) 
    { 
     return false; 
    } 

    for (int i = 0; i < x.Count; i++) 
    { 
     if (!x[i].Equals(y[i])) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

El nerd en mí también se arrastró así que hice una prueba de rendimiento contra SequenceEquals, y este tiene una ligera ventaja.

Ahora, la pregunta a hacer; ¿Es esta ganancia de rendimiento pequeña, casi mensurable, válida para agregar el código a la base de código y mantenerlo? Lo dudo mucho; o)

1

Se puede escribir un propósito general IEqualityComparer<T> para las secuencias. Una simple:

public class SequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>> 
{ 
    public bool Equals(IEnumerable<T> x, IEnumerable<T> y) 
    { 
     return x.SequenceEqual(y); 
    } 

    public int GetHashCode(IEnumerable<T> obj) 
    { 
     return unchecked(obj.Aggregate(397, (x, y) => x * 31 + y.GetHashCode())); 
    } 
} 

A más concretarse versión: que debería ser mejor rendimiento.

public class SequenceEqualityComparer<T> : EqualityComparer<IEnumerable<T>>, 
              IEquatable<SequenceEqualityComparer<T>> 
{ 
    readonly IEqualityComparer<T> comparer; 

    public SequenceEqualityComparer(IEqualityComparer<T> comparer = null) 
    { 
     this.comparer = comparer ?? EqualityComparer<T>.Default; 
    } 

    public override bool Equals(IEnumerable<T> x, IEnumerable<T> y) 
    { 
     // safer to use ReferenceEquals as == could be overridden 
     if (ReferenceEquals(x, y)) 
      return true; 

     if (x == null || y == null) 
      return false; 

     var xICollection = x as ICollection<T>; 
     if (xICollection != null) 
     { 
      var yICollection = y as ICollection<T>; 
      if (yICollection != null) 
      { 
       if (xICollection.Count != yICollection.Count) 
        return false; 

       var xIList = x as IList<T>; 
       if (xIList != null) 
       { 
        var yIList = y as IList<T>; 
        if (yIList != null) 
        { 
         // optimization - loops from bottom 
         for (int i = xIList.Count - 1; i >= 0; i--) 
          if (!comparer.Equals(xIList[i], yIList[i])) 
           return false; 

         return true; 
        } 
       } 
      } 
     } 

     return x.SequenceEqual(y, comparer); 
    } 

    public override int GetHashCode(IEnumerable<T> sequence) 
    { 
     unchecked 
     { 
      int hash = 397; 
      foreach (var item in sequence) 
       hash = hash * 31 + comparer.GetHashCode(item); 

      return hash; 
     } 
    } 

    public bool Equals(SequenceEqualityComparer<T> other) 
    { 
     if (ReferenceEquals(null, other)) 
      return false; 

     if (ReferenceEquals(this, other)) 
      return true; 

     return this.comparer.Equals(other.comparer); 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as SequenceEqualityComparer<T>); 
    } 

    public override int GetHashCode() 
    { 
     return comparer.GetHashCode(); 
    } 
} 

Esto tiene algunas características:

  1. La comparación se realiza de abajo hacia arriba. Hay más probabilidad de que las colecciones difieran al final en casos de uso típicos.

  2. Se puede pasar un IEqualityComparer<T> para basar la comparación de los artículos de la colección.

0

Uso linqSequenceEqual para comprobar la igualdad secuencia porque Igual método comprueba por la igualdad de referencia.

bool isEqual = list1.SequenceEqual(list2); 

El método SequenceEqual() toma una segunda secuencia I Enumerable<T> como un parámetro, y realiza una comparación, (primera) secuencia de elemento por elemento, con el objetivo. Si las dos secuencias contienen el mismo número de elementos, y cada elemento en la primera secuencia es igual al elemento correspondiente en la segunda secuencia (usando el comparador de igualdad predeterminado ) entonces SequenceEqual()returns true. De lo contrario, se devuelve false.

O si no se preocupan por elementos de orden utilización Enumerable.All método:

var isEqual = list1.All(list2.Contains); 

La segunda versión requiere también otro cheque para el conde, ya que volvería cierto incluso si list2 contiene más elementos que list1.

Cuestiones relacionadas