Подтвердить что ты не робот

Каков наилучший способ проверить два списка List <T> для равенства в С#

Есть много способов сделать это, но я чувствую, что упустил какую-то функцию или что-то в этом роде.

Очевидно, что List == List будет использовать Object.Equals() и вернуть false.

Если каждый элемент списка равен и присутствует в том же месте в противоположном списке, я бы счел их равными. Я использую типы значений, но правильно реализованный объект Data должен работать одинаково (я не ищу мелкий скопированный список, только то, что значение каждого объекта внутри одинаково).

Я пробовал поиск и есть похожие вопросы, но мой вопрос - это равенство каждого элемента в точном порядке.

4b9b3361

Ответ 1

Enumerable.SequenceEqual<TSource>

MSDN

Ответ 2

Реализация зла

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

Ответ 3

Я собрал эту вариацию:

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

Ботаник во мне также отсканировал, поэтому я провел тест производительности с SequenceEquals, и у этого есть небольшое преимущество.

Теперь зададим вопрос; это крошечный, почти измеримый прирост производительности, который стоит добавить код в базу кода и поддерживать его? Я очень сомневаюсь в этом: o)

Ответ 4

Я выбил быстрый метод расширения:

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

Ответ 5

Можно написать общую последовательность IEqualityComparer<T> для последовательностей. Простой:

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

Более сложная версия: это должно быть лучше.

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

Это имеет несколько особенностей:

  • Сравнение выполняется снизу вверх. В типичных случаях использования существует большая вероятность того, что коллекции будут отличаться в конце.

  • А IEqualityComparer<T> можно передать, чтобы основывать сравнение для элементов в коллекции.

Ответ 6

Используйте linq SequenceEqual, чтобы проверить равенство последовательности, потому что метод Equals проверяет ссылочное равенство.

bool isEqual = list1.SequenceEqual(list2);

Метод SequenceEqual() принимает вторую последовательность я Enumerable<T> в качестве параметра и выполняет сравнение по элементам с целевой (первой) последовательностью. Если две последовательности содержат одинаковое число элементов, и каждый элемент в первой последовательности равен соответствующему элементу во второй последовательности (с использованием сравнения по умолчанию), тогда SequenceEqual() returns true. В противном случае возвращается false.

Или, если вам не нужен порядок элементов, используйте метод Enumerable.All:

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

Вторая версия также требует другой проверки для Count, потому что она вернет true, даже если list2 содержит больше элементов, чем list1.