Утверждение двух List <List <T>> эквивалентно друг другу
Чтобы убедиться, что два списка одинаковы, в nunit мы можем использовать CollectionAssert.AreEquivalent
, чтобы проверить, что эти два списка содержат одинаковые элементы (порядки не важны).
Но как проверить, эквивалентны ли два List<List<T>>
? Идея состоит в том, что если один List<T>
имеет те же элементы, что и другие List<T>
(опять же, порядок не важен), то они равны.
Ответы
Ответ 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);
}
Обратите внимание, что это очень наивная реализация только, сглаженные последовательности могут быть равны, в то время как исходные последовательности содержат одни и те же элементы, но в другом разбиении.