Сравнение двух списков <string>на равенство - PullRequest
60 голосов
/ 10 октября 2009

Помимо пошагового прохождения элементов по одному, как сравнить два списка строк на равенство (в .NET 3.0):

Это не удалось:

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

Ответы [ 9 ]

76 голосов
/ 10 октября 2009

Попробуйте следующее

var equal = expected.SequenceEqual(actual);

Тестовая версия

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

Метод расширения SequenceEqual будет сравнивать элементы коллекции в порядке равенства.

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

40 голосов
/ 10 октября 2009

Многие тестовые среды предлагают класс CollectionAssert:

CollectionAssert.AreEqual(expected, actual);

Eg MS Test

12 голосов
/ 10 октября 2009

Вы всегда можете написать нужную функцию самостоятельно:

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

и используйте его:

// 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) );
10 голосов
/ 10 октября 2009

Я заметил, что на самом деле никто не сказал вам, почему ваш оригинальный код не работает. Это связано с тем, что оператор == в общем тестирует ссылочное равенство (т. Е. Если два экземпляра указывают на один и тот же объект в памяти), если оператор не был перегружен . List<T> не определяет оператор ==, поэтому используется базовая ссылка, равная реализации.

Как показали другие постеры, вам, как правило, придется проходить через элементы, чтобы проверить «равенство коллекций». Конечно, вы должны использовать оптимизацию, предложенную пользователем DreamWalker , которая сначала проверяет количество коллекций, прежде чем проходить через них.

5 голосов
/ 21 января 2016

Если заказ имеет значение:

bool equal = a.SequenceEquals(b);

Если заказ не имеет значения:

bool equal = a.Count == b.Count && new HashSet<string>(a).SetEquals(b);
1 голос
/ 25 октября 2015

Использование Linq и написание кода в качестве метода расширения:

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();
}
1 голос
/ 10 октября 2009

Вы можете написать метод расширения следующим образом:

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

И назовите это так:

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

РЕДАКТИРОВАТЬ: обновлен код для использования вместо статического метода, так как OP использует .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;
        }

Клиент:

        bool isEqual = IsEqual(intList,targetList, Comparer<int>.Default);
0 голосов
/ 30 мая 2019

Может использоваться не обычным способом, но без реализации IEquatable для пользовательских типов

JsonConvert.SerializeObject( myList1) == JsonConvert.SerializeObject( myList2)

Но в общем случае вы можете использовать SequenceEqual, как упоминалось в комментариях https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.8

Также не забудьте реализовать интерфейс IEquatable для пользовательских типов (не обязательно для типа строк или другой структуры)

0 голосов
/ 28 сентября 2015

Хотя он выполняет итерацию по коллекции, этот созданный мной метод расширения не требует, чтобы порядок двух списков был одинаковым, и он также работает со сложными типами, пока метод Equals переопределяется.

Следующие два списка вернули бы true:

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

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

Метод:

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