a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
a и b следует считать равными, потому что они имеют точно такие же элементы, только в разном порядке.
Дело в том, что мои фактические списки будут состоять из объектов (экземпляров моих классов), а не целых чисел.
python
algorithm
list
comparison
Johndir
источник
источник
len()
Сначала можно проверить .Ответы:
O (n) : лучше всего подходит метод Counter () (если ваши объекты хешируются):
def compare(s, t): return Counter(s) == Counter(t)
O (n log n) : метод sorted () является следующим лучшим (если ваши объекты можно заказать):
def compare(s, t): return sorted(s) == sorted(t)
O (n * n) : если объекты нельзя ни хэшировать, ни упорядочивать, можно использовать равенство:
def compare(s, t): t = list(t) # make a mutable copy try: for elem in s: t.remove(elem) except ValueError: return False return not t
источник
sorted()
, по общему признанию, не зная об этомCounter
. Интервьюер настаивал на том, что существует более эффективный метод, и я явно ничего не сделал. После обширного тестирования на Python 3 сtimeit
модулем, сортировка последовательно выполняется быстрее в списках целых чисел. В списках из 1 тыс. Пунктов примерно на 1,5% медленнее, а в коротких списках - 10 элементов - на 7,5% медленнее. Мысли?python3.6 -m timeit -s 'from collections import Counter' -s 'from random import shuffle' -s 't=list(range(100)) * 5' -s 'shuffle(t)' -s 'u=t[:]' -s 'shuffle(u)' 'Counter(t)==Counter(u)'
sorted vs counter
... Мне очень любопытно, что здесь происходит.Вы можете отсортировать оба:
Подсчета рода также может быть более эффективным (но это требует , чтобы объект быть hashable).
>>> from collections import Counter >>> a = [1, 2, 3, 1, 2, 3] >>> b = [3, 2, 1, 3, 2, 1] >>> print (Counter(a) == Counter(b)) True
источник
__hash__
, но это может быть невозможно для коллекций.sorted([0, 1j])
Если вы знаете, что элементы всегда могут быть хешированы, вы можете использовать a, равное
Counter()
O (n).Если вы знаете, что элементы всегда можно сортировать, вы можете использовать значение
sorted()
O (n log n)В общем случае вы не можете полагаться на возможность сортировки или наличие элементов, поэтому вам нужен такой запасной вариант, который, к сожалению, O (n ^ 2)
len(a)==len(b) and all(a.count(i)==b.count(i) for i in a)
источник
Лучший способ сделать это - отсортировать списки и сравнить их. (Использование
Counter
не будет работать с объектами, которые не хешируются.) Это просто для целых чисел:С произвольными объектами становится немного сложнее. Если вы заботитесь об идентичности объекта, то есть о том, находятся ли одни и те же объекты в обоих списках, вы можете использовать эту
id()
функцию в качестве ключа сортировки.(В Python 2.x вам фактически не нужен
key=
параметр, потому что вы можете сравнивать любой объект с любым объектом. Порядок произвольный, но стабильный, поэтому он отлично подходит для этой цели; не имеет значения, в каком порядке находятся объекты in, только порядок одинаков для обоих списков. Однако в Python 3 сравнение объектов разных типов запрещено во многих случаях - например, вы не можете сравнивать строки с целыми числами - поэтому, если у вас будут объекты различных типов, лучше всего явно использовать идентификатор объекта.)С другой стороны, если вы хотите сравнить объекты в списке по значению, сначала вам нужно определить, что означает «значение» для объектов. Затем вам понадобится какой-то способ предоставить это в качестве ключа (а для Python 3 - как согласованный тип). Один из возможных способов, который сработает для множества произвольных объектов, - это сортировка по их
repr()
. Конечно, это может привести к потере уймы лишнего времени иrepr()
строк построения памяти для больших списков и так далее.Если все объекты относятся к вашим собственным типам, вы можете определить
__lt__()
их, чтобы объект знал, как сравнивать себя с другими. Тогда вы можете просто отсортировать их и не беспокоиться оkey=
параметре. Конечно, вы также можете определить__hash__()
и использоватьCounter
, что будет быстрее.источник
Если вам нужно сделать это в тестах: https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual
assertCountEqual(first, second, msg=None)
Проверьте, что первая последовательность содержит те же элементы, что и вторая, независимо от их порядка. В противном случае будет сгенерировано сообщение об ошибке с указанием различий между последовательностями.
Повторяющиеся элементы не игнорируются при сравнении первого и второго. Он проверяет, имеет ли каждый элемент одинаковое количество в обеих последовательностях. Эквивалентно: assertEqual (Counter (list (first)), Counter (list (second))), но также работает с последовательностями нехэшируемых объектов.
Новое в версии 3.2.
или в 2.7: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual
Вне тестов я бы порекомендовал этот
Counter
метод.источник
Если список содержит элементы, которые не могут быть хешированы (например, список объектов), вы можете использовать класс Counter и функцию id (), например:
from collections import Counter ... if Counter(map(id,a)) == Counter(map(id,b)): print("Lists a and b contain the same objects")
источник
Я надеюсь, что приведенный ниже фрагмент кода может сработать в вашем случае: -
if ((len(a) == len(b)) and (all(i in a for i in b))): print 'True' else: print 'False'
Это гарантирует, что все элементы в обоих списках
a
&b
будут одинаковыми, независимо от того, находятся они в одном порядке или нет.Для лучшего понимания обратитесь к моему ответу на этот вопрос
источник
Если сравнение должно выполняться в контексте тестирования, используйте
assertCountEqual(a, b)
(py>=3.2
) иassertItemsEqual(a, b)
(2.7<=py<3.2
).Также работает с последовательностями нехэшируемых объектов.
источник
Пусть a, b списки
def ass_equal(a,b): try: map(lambda x: a.pop(a.index(x)), b) # try to remove all the elements of b from a, on fail, throw exception if len(a) == 0: # if a is empty, means that b has removed them all return True except: return False # b failed to remove some items from a
Нет необходимости делать их хэшируемыми или сортировать.
источник
a
поддержкиpop
(изменяемый) иindex
(является последовательностью). Raymond не предполагает ни того, ни другого, в то время как gnibbler предполагает только последовательность.Использование
unittest
модуля дает вам чистый и стандартный подход.import unittest test_object = unittest.TestCase() test_object.assertCountEqual(a, b)
источник