En plus de parcourir les éléments un par un, comment comparer deux listes de chaînes pour l'égalité (dans .NET 3.0):
Cela échoue:
// 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 );
De nombreux frameworks de test proposent une classe CollectionAssert:
CollectionAssert.AreEqual(expected, actual);
Par exemple MS Test
Essayez ce qui suit
var equal = expected.SequenceEqual(actual);
Version de test
Assert.IsTrue( actual.SequenceEqual(expected) );
La méthode d'extension SequenceEqual comparera les éléments de la collection par égalité.
Voir http://msdn.Microsoft.com/en-us/library/bb348567 (v = vs.100) .aspx
Vous pouvez toujours écrire eux-mêmes la fonction requise:
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;
}
et l'utiliser:
// 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) );
J'ai remarqué que personne ne vous a vraiment expliqué pourquoi votre code d'origine ne fonctionnait pas. C'est parce que le ==
opérateur dans les tests généraux égalité de référence (c'est-à-dire si les deux instances pointent vers le même objet en mémoire) sauf si l'opérateur a été surchargé . List<T>
ne définit pas un ==
L'opérateur utilise donc la référence de base égale à l'implémentation.
Comme d'autres affiches l'ont démontré, vous devrez généralement parcourir les éléments pour tester "l'égalité des collections". Bien sûr, vous devez utiliser l'optimisation suggérée par l'utilisateur DreamWalker qui teste d'abord le nombre de collections avant de les parcourir.
Si la commande est importante:
bool equal = a.SequenceEquals(b);
Si la commande n'a pas d'importance:
bool equal = a.Count == b.Count && new HashSet<string>(a).SetEquals(b);
Vous pouvez écrire une méthode d'extension comme ceci:
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;
}
}
Et appelez-le ainsi:
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: mise à jour du code pour utiliser une méthode statique à la place car OP utilise .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;
}
Client:
bool isEqual = IsEqual(intList,targetList, Comparer<int>.Default);
Utiliser Linq et écrire le code comme méthode d'extension:
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();
}
Bien qu'elle itère sur la collection, cette méthode d'extension que j'ai créée ne nécessite pas que l'ordre des deux listes soit le même, et elle fonctionne également avec les types complexes, tant que la méthode Equals est remplacée.
Les deux listes suivantes renverraient true:
List<string> list1 = new List<string>
{
{ "bob" },
{ "sally" },
{ "john" }
};
List<string> list2 = new List<string>
{
{ "sally" },
{ "john" },
{ "bob" }
};
Méthode:
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();
}
Il peut être utilisé de manière non régulière mais sans implémentation IEquatable pour les types personnalisés
JsonConvert.SerializeObject( myList1) == JsonConvert.SerializeObject( myList2)
Mais dans le cas général, vous pouvez utiliser SequenceEqual comme cela a été mentionné dans les commentaires https://docs.Microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.8 =
N'oubliez pas non plus d'implémenter l'interface IEquatable pour les types personnalisés (pas nécessaire pour le type de chaînes ou autre structure)