Как эффективно сравнить два неупорядоченных списка (не наборы) в Python?
a = [1, 2, 3, 1, 2, 3]
b = [3, 2, 1, 3, 2, 1]
a & b следует считать равными, потому что они имеют точно такие же элементы, только в другом порядке.
дело в том, что мои фактические списки будут состоять из объектов (экземпляров моего класса), а не целых чисел.
9 ответов:
O (n): The счетчик() метод лучше всего (если ваши объекты хэшируются):
def compare(s, t): return Counter(s) == Counter(t)
O (N log n): The отсортированный() метод следующий лучший (если ваши объекты упорядочиваются):
def compare(s, t): return sorted(s) == sorted(t)
O (n * n): если объекты не hashable, не доступен, вы можете использовать равенства:
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(a) == sorted(b)
A подсчет вроде также может быть более эффективным (но и она требует объекта, который должен быть 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
Если вы знаете, что элементы всегда хэшируются, вы можете использовать
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
не работает с объектами, которые не hashable.) Это просто для целых чисел:sorted(a) == sorted(b)
это становится немного сложнее с произвольными объектами. Если вы заботитесь об идентичности объекта, то есть, является ли то же самое объекты находятся в обоих списках, вы можете использовать
Если список содержит элементы, которые не hashable (например, список объектов), вы могли бы использовать Счетчик Класс и функция id (), такие как:
from collections import Counter ... if Counter(map(id,a)) == Counter(map(id,b)): print("Lists a and b contain the same objects")
если сравнение должно выполняться в контексте тестирования, используйте
assertCountEqual(a, b)
(py>=3.2
) иassertItemsEqual(a, b)
(2.7<=py<3.2
).работает на последовательностях недоступных объектов тоже.
https://docs.python.org/3.5/library/unittest.html#unittest.TestCase.assertCountEqual
assertCountEqual(первый, второй, msg=нет)
проверьте, что первая последовательность содержит те же элементы, что и вторая, независимо от их порядка. Когда они этого не делают, будет сгенерировано сообщение об ошибке с перечислением различий между последовательностями.
повторяющиеся элементы не игнорируются при сравнении первого и второго. Он проверяет, имеет ли каждый элемент то же самое количество в обеих последовательностях. Эквивалентно: assertEqual(Counter(list(first)), Counter(list (second))) но также работает с последовательностями недоступных объектов.
новое в версии 3.2.
или в 2.7: https://docs.python.org/2.7/library/unittest.html#unittest.TestCase.assertItemsEqual
пусть 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
Не нужно делать из них hashable или отсортировать их.
Я надеюсь, что ниже кусок кода может работать в вашем случае :-
if ((len(a) == len(b)) and (all(i in a for i in b))): print 'True' else: print 'False'
Это гарантирует, что все элементы в обоих списках
a
&b
такие же, независимо от того, находятся ли они в том же порядке или нет.для лучшего понимания, обратитесь к моему ответу в этот вопрос