Проверьте, равны ли два неупорядоченных списка

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

Например:

['one', 'two', 'three'] == ['one', 'two', 'three'] :  true
['one', 'two', 'three'] == ['one', 'three', 'two'] :  true
['one', 'two', 'three'] == ['one', 'two', 'three', 'three'] :  false
['one', 'two', 'three'] == ['one', 'two', 'three', 'four'] :  false
['one', 'two', 'three'] == ['one', 'two', 'four'] :  false
['one', 'two', 'three'] == ['one'] :  false

Я надеюсь сделать это без использования карты.

Ответ 1

Python имеет встроенный тип данных для неупорядоченного набора (хешируемых) вещей, называемого set. Если вы конвертируете оба списка в наборы, сравнение будет неупорядоченным.

set(x) == set(y)

Документация на set


EDIT: @mdwhatcott указывает, что вы хотите проверить наличие дубликатов. set игнорирует их, поэтому вам нужна аналогичная структура данных, которая также отслеживает количество элементов в каждом списке. Это называется multiset; наилучшим приближением в стандартной библиотеке является collections.Counter:

>>> import collections
>>> compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
>>> 
>>> compare([1,2,3], [1,2,3,3])
False
>>> compare([1,2,3], [1,2,3])
True
>>> compare([1,2,3,3], [1,2,2,3])
False
>>> 

Ответ 2

Если элементы всегда сортируются по порядку, как в вашем примере, то встроенная .sort() (timsort) должна быть быстрой:

>>> a = [1,1,2]
>>> b = [1,2,2]
>>> a.sort()
>>> b.sort()
>>> a == b
False

Если вы не хотите сортировать inplace, вы можете использовать sorted().

На практике это всегда будет быстрее, чем collections.Counter() (несмотря на асимптотически O(n) время лучше, чем O(n*log(n)) для .sort()). Измерьте это; Если это важно.

Ответ 3

sorted(x) == sorted(y)

Копирование здесь: Проверьте, равны ли два неупорядоченных списка

Я думаю, что это лучший ответ на этот вопрос, потому что

  • Это лучше, чем использование счетчика, как указано в этом ответе
  • x.sort() сортирует x, что является побочным эффектом. sorted (x) возвращает новый список.

Ответ 4

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

Вы можете использовать набор:

>>> set(['one', 'two', 'three']) == set(['two', 'one', 'three'])
True

Но сам объект set будет содержать только один экземпляр каждого уникального значения и не сохранит порядок.

>>> set(['one', 'one', 'one']) == set(['one'])
True

Итак, если отслеживание дубликатов/длина важна, вы, вероятно, захотите также проверить длину:

def are_eq(a, b):
    return set(a) == set(b) and len(a) == len(b)

Ответ 5

если вы не хотите использовать библиотеку коллекций, вы всегда можете сделать что-то вроде этого: что a и b являются вашими списками, следующее возвращает количество соответствующих элементов (он рассматривает порядок).

sum([1 for i,j in zip(a,b) if i==j])

Следовательно,

len(a)==len(b) and len(a)==sum([1 for i,j in zip(a,b) if i==j])

будет True, если оба списка совпадают, содержат одни и те же элементы и в том же порядке. False в противном случае.

Итак, вы можете определить функцию сравнения, такую ​​как первый ответ выше, но без библиотеки коллекций.

compare = lambda a,b: len(a)==len(b) and len(a)==sum([1 for i,j in zip(a,b) if i==j])

и

>>> compare([1,2,3], [1,2,3,3])
False
>>> compare([1,2,3], [1,2,3])
True
>>> compare([1,2,3], [1,2,4])
False

Ответ 6

Ответ одного лайнера на вышеупомянутый вопрос: -

пусть два списка будут list1 и list2, и ваше требование состоит в том, чтобы убедиться, что в двух списках есть одни и те же элементы, тогда, как и я, следующий подход будет наилучшим: -

if ((len(list1) == len(list2)) and
   (all(i in list2 for i in list1))):
    print 'True'
else:
    print 'False'

Вышеупомянутый фрагмент кода будет работать в соответствии с вашими потребностями, то есть все ли элементы списка1 находятся в списке2 и наоборот.

Но если вы хотите просто проверить, присутствуют ли все элементы list1 в списке2 или нет, тогда вам нужно использовать только следующую часть кода: -

if all(i in list2 for i in list1):
    print 'True'
else:
    print 'False'

Разница в том, что позже будет напечатан True, если в списке2 есть дополнительные элементы вместе со всеми элементами списка1. Простыми словами, он гарантирует, что все элементы списка1 должны присутствовать в списке2, независимо от того, есть ли в списке2 некоторые дополнительные элементы или нет.

Ответ 7

Предполагая, что вы уже знаете, что списки имеют одинаковый размер, следующее гарантирует True, если и только если два вектора абсолютно одинаковы (включая порядок)

functools.reduce(lambda b1,b2: b1 and b2, map(lambda e1,e2: e1==e2, listA, ListB), True)

Пример:

>>> from functools import reduce
>>> def compvecs(a,b):
...     return reduce(lambda b1,b2: b1 and b2, map(lambda e1,e2: e1==e2, a, b), True)
... 
>>> compvecs(a=[1,2,3,4], b=[1,2,4,3])
False
>>> compvecs(a=[1,2,3,4], b=[1,2,3,4])
True
>>> compvecs(a=[1,2,3,4], b=[1,2,4,3])
False
>>> compare_vectors(a=[1,2,3,4], b=[1,2,2,4])
False
>>> 

Ответ 8

Как получить строковое представление списков и их сравнение?

>>> l1 = ['one', 'two', 'three']
>>> l2 = ['one', 'two', 'three']
>>> l3 = ['one', 'three', 'two']
>>> print str(l1) == str(l2)
True
>>> print str(l1) == str(l3)
False