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

Утверждение двух List <List <T>> эквивалентно друг другу

Чтобы убедиться, что два списка одинаковы, в nunit мы можем использовать CollectionAssert.AreEquivalent, чтобы проверить, что эти два списка содержат одинаковые элементы (порядки не важны).

Но как проверить, эквивалентны ли два List<List<T>>? Идея состоит в том, что если один List<T> имеет те же элементы, что и другие List<T> (опять же, порядок не важен), то они равны.

4b9b3361

Ответ 1

Вам нужно пройти через них, чтобы убедиться, что они эквивалентны, но с некоторыми важными ярлыками:

  • Если они на самом деле являются одним и тем же экземпляром (и в реальном коде это часто появляется), то ReferenceEquals(x, y) вернет true. В противном случае это не произойдет. Если ReferenceEquals возвращает true, то они эквивалентны.

  • Если один из них является нулевым, а другой - нет, то, очевидно, они не равны (если они равны нулю, вы поймете это выше с помощью ReferenceEquals). В любом случае вам потребуется протестировать нуль для обеспечения безопасности, поэтому во многих случаях у вас есть еще один короткий ответ.

  • Если они имеют разные размеры, то (для большинства определений эквивалентности есть исключения) они не равны. Немедленно возвращайте false.

  • В тот момент, когда вы обнаружили несоответствие, вы можете вернуть false, не продолжая проверять.

  • Быстрее сравнить их, если они уже отсортированы. Если вы можете сохранить их сортировку или не дать понять, сортируются они или нет, а затем сортировать только по мере необходимости, вы можете значительно ускорить процесс. (Обратите внимание, что многие алгоритмы сортировки имеют худшее поведение при ненужной сортировке списка, который уже отсортирован).

Ответ 2

Здесь попытка, не протестированная. Если каждый внутренний список содержит элементы m, а внешний список list содержит списки n, я считаю, что сложность O (n^2 x m), но я могу ошибаться. Предположения:

  • T не реализует IComparable или любой такой интерфейс, который позволяет сортировать.
  • Заказ не имеет отношения к равенству как для объектов List<List<T>>, так и для компоновки List<T>.

-

public static bool ListListsAreEqual<T>(List<List<T>> listlist1, List<List<T>> listlist2)
{
    if (listlist1.Count != listlist2.Count)
        return false;

    var listList2Clone = listlist2.ToList();

    foreach (var list1 in listlist1)
    {
        var indexOfMatchInList2 = listList2Clone
                   .FindIndex(list2 => ListsArePermutations(list1, list2));

        if (indexOfMatchInList2 == -1)
            return false;

        listList2Clone.RemoveAt(indexOfMatchInList2);
    }

    return true;
}

private static bool ListsArePermutations<T>(List<T> list1, List<T> list2)
{
    return list1.Count == list2.Count && new HashSet<T>(list1).SetEquals(list2);
}

Ответ 3

Я не думаю, что вы обойдете каждый элемент отдельно. Обычно я сначала проверяю на равную длину, затем цикл для say я по длине списков и проверю, что list1 [i] == list2 [i]

Обновление

Извините, пропустил (центральную) часть о том, что элементы не должны быть в порядке. В этом случае создайте HashSet с элементами второго списка и проверьте каждый элемент в списке1, если он находится в hashset. Это уменьшает время работы для поиска от линейного до логарифмического.

обновление 2 Как отметил Дональд Рэй, вам нужно проверить оба способа, если у вас есть возможность множественного появления отдельных объектов в любом из списков.

Ответ 4

Я думаю, вам нужно будет написать свой собственный код, чтобы сделать это.

Посмотрите, как CollectionAssert.AreEquivalent работает с Reflector, а затем напишите свой собственный вспомогательный класс "MyAsserts".

Вам нужно быть умным, если вы хотите работать быстрее, чем O (n ^ 2 * m ^ 2), где n - количество списков в крайнем списке, а m - количество элементов во внутренних списках.

Простым решением является цикл над всеми "внутренними списками" в списке1 и использование кода из CollectionAssert.AreEquivalent, чтобы проверить, содержит ли list2 такой список. Затем замените list1 и list2 и повторите. Однако вы можете сделать намного лучше.

(Затем вам нужно выяснить, как создать полезное сообщение, если списки не эквивалентны.)

Ответ 5

Я бы использовал SelectMany() и сгладил список. Теперь вы можете либо сравнить элемент с элементом, используя Assert.Equals(), либо использовать нормальный сборщик для списков. Выражение запроса с двумя из предложений будет делать то же самое:

void AssertEquals<T>(List<List<T>> expected, List<List<T>> actual)
{
  var flatExpected = expected.SelectMany(x=>x);
  var flatActual = expected.SelectMany(x=>x);

  CollectionAssert.Equals(flatExpected, flatActual);
}

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