2009-10-10 38 views
56

Aparte de pasar a través de los elementos uno por uno, ¿cómo comparar dos listas de cadenas por la igualdad (en .NET 3.0):comparar dos lista <string> por la igualdad

esto falla:

// Expected result. 
List<string> expected = new List<string>(); 
expected.Add("a"); 
expected.Add("b"); 
expected.Add("c"); 

// Actual result 
actual = new List<string>(); 
actual.Add("a"); 
actual.Add("b"); 
actual.Add("c"); 

// Verdict 
Assert.IsTrue(actual == expected); 
+0

posible duplicado de [¿Cuál es la mejor manera de comprobar dos Lista listas para la igualdad en C#] (http://stackoverflow.com/questions/876508/what-is-the-best-way-to-check-two-listt-lists-for-equality-in-c-sharp) – nawfal

Respuesta

40

Muchos marcos de prueba ofrecen una clase CollectionAssert:

CollectionAssert.AreEqual(expected, actual); 

Ej MS Test

+0

Por desgracia, los mensajes que da cuando falla son ligeramente inútiles, por ej. "Diferentes cantidades de elementos" o "Elemento en el índice 0 no coinciden", sin decirle * qué son *. –

73

Pruebe lo siguiente

var equal = expected.SequenceEqual(actual); 

prueba Versión

Assert.IsTrue(actual.SequenceEqual(expected)); 

El método de extensión SequenceEqual comparará los elementos de la colección para garantizar la igualdad.

Ver http://msdn.microsoft.com/en-us/library/bb348567(v=vs.100).aspx

+0

Thansk por su respuesta. ¿Es eso .NET 3.5 solamente? Olvidé mencionar que estoy usando .NET 3.0. –

+0

@ Adam, sí. SequenceEquals es un método de extensión definido en 3.5, aunque es bastante fácil de trasladar a un proyecto 2.0. – JaredPar

+0

No le dará detalles sobre por qué las colecciones son diferentes, mientras que CollectionAssert.AreEqual() lo hará. –

12

Siempre se puede escribir la función necesaria a sí mismos:

public static bool ListEquals<T>(IList<T> list1, IList<T> list2) { 
    if (list1.Count != list2.Count) 
     return false; 
    for (int i = 0; i < list1.Count; i++) 
     if (!list1[i].Equals(list2[i])) 
      return false; 
    return true; 
} 

y utilizarlo :

// Expected result. 
List<string> expected = new List<string>(); 
expected.Add("a"); 
expected.Add("b"); 
expected.Add("c"); 

// Actual result 
actual = new List<string>(); 
actual.Add("a"); 
actual.Add("b"); 
actual.Add("c"); 

// Verdict 
Assert.IsTrue(ListEquals(actual, expected)); 
+0

¡Agradable! Estaba buscando evitar pasar por los elementos, pero esa es una gran forma genérica en la que escribiste el método. –

+0

Votificado, esta es una buena respuesta. Sin embargo, tenga en cuenta que la función arrojará una excepción si cualquiera de las listas es nula. Recomendamos agregar las siguientes declaraciones al comienzo de la función: 'if (list1 == null && list2 == null) return true;' y 'if (list1 == null || list2 == null) return false;' –

10

Noté que nadie realmente le dijo por qué su código original no funcionaba. Esto se debe a que el operador == en general prueba reference equality (es decir, si las dos instancias apuntan al mismo objeto en la memoria) a menos que el operador haya sido overloaded. List<T> no define un operador == por lo que se utiliza la referencia base igual a la implementación.

Como han demostrado otros carteles, generalmente tendrá que pasar por elementos para probar la "igualdad de colección". Por supuesto, debe usar la optimización sugerida por el usuario DreamWalker que primero prueba el recuento de las colecciones antes de recorrerlas.

+0

Gracias ¡tú! Podría pensar en varias formas de hacer la comparación yo mismo, pero cuando me encontré con este problema, pensé: "Bueno, obviamente no se está buscando la igualdad, entonces, ¿qué está haciendo?". – JHixson

1

Se puede escribir un método de extensión de este modo:

public static class ListExtensions 
    { 
     public static bool IsEqual<T>(this IList<T> list,IList<T> target, IComparer<T> comparer) where T:IComparable<T> 
     { 
      if (list.Count != target.Count) 
      { 
       return false; 
      } 
      int index = 0; 
      while (index < list.Count && 
        comparer.Compare(list[index],target[index]) == 0) 
      { 
       index++; 
      } 
      if (index != list.Count) 
      { 
       return false; 
      } 
      return true; 
     } 
    } 

y lo llaman así:

List<int> intList = new List<int> { 1, 234, 2, 324, 324, 2 }; 
List<int> targetList = new List<int> { 1, 234, 2, 324, 324 }; 
bool isEqual = intList.IsEqual(targetList, Comparer<int>.Default); 

EDIT: Se ha actualizado el código para utilizar un método estático en lugar OP ya está utilizando .NET 3,0

public static bool IsEqual<T>(IList<T> sourceList, IList<T> targetList, IComparer<T> comparer) where T : IComparable<T> 
     { 
      if (sourceList.Count != targetList.Count) 
      { 
       return false; 
      } 
      int index = 0; 
      while (index < sourceList.Count && 
        comparer.Compare(sourceList[index], targetList[index]) == 0) 
      { 
       index++; 
      } 
      if (index != sourceList.Count) 
      { 
       return false; 
      } 
      return true; 
     } 

Cliente:

 bool isEqual = IsEqual(intList,targetList, Comparer<int>.Default); 
+0

¿Está permitido en .NET 3.0? –

+0

@Adam: me di cuenta de que estás usando .NET 3.0 y no .NET 3.5. Editaré mi respuesta para hacer que el código sea utilizable para .NET 3.0 al convertirlo en un método estático en lugar de en un método de extensión. –

0

Si bien itera sobre la colección, este método de extensión que he creado no requiere que el orden de las dos listas sea el mismo, y también funciona con tipos complejos, siempre que se anule el método Equals.

Los siguientes dos listas volverían cierto:

List<string> list1 = new List<string> 
{ 
    { "bob" }, 
    { "sally" }, 
    { "john" } 
}; 

List<string> list2 = new List<string> 
{ 
    { "sally" }, 
    { "john" }, 
    { "bob" } 
}; 

Método:

public static bool IsEqualTo<T>(this IList<T> list1, IList<T> list2) 
{ 
    if (list1.Count != list2.Count) 
    { 
     return false; 
    } 

    List<T> list3 = new List<T>(); 

    foreach (var item in list2) 
    { 
     list3.Add(item); 
    } 

    foreach (var item in list1) 
    { 
     int index = -1; 
     for (int x = 0; x < list3.Count; x++) 
     { 
      if (list3[x].Equals(item)) 
      { 
       index = x; 
      } 
     } 

     if (index > -1) 
     { 
      list3.RemoveAt(index); 
     } 
     else 
     { 
      return false; 
     } 
    } 

    return !list3.Any(); 
} 
1

El uso de LINQ y escribir el código como un método de extensión:

public static bool EqualsOtherList<T>(this List<T> thisList, List<T> theOtherList) 
{ 
    if (thisList == null || theOtherList == null || 
     thisList.Count != theOtherList.Count) return false; 
    return !thisList.Where((t, i) => !t.Equals(theOtherList[i])).Any(); 
} 
5

Si las cuestiones de orden :

bool equal = a.SequenceEquals(b); 

Si la orden no tiene importancia:

bool equal = a.Count == b.Count && new HashSet<string>(a).SetEquals(b); 
Cuestiones relacionadas