Быстрый способ найти количество элементов в пересечении списков (Python)
Есть ли более быстрый способ вычислить это значение в Python:
len([x for x in my_list if x in other_list])
Я попытался использовать наборы, так как элементы списков уникальны, но я не заметил никакой разницы.
len(set(my_list).intersection(set(other_list)))
Я работаю с большими списками, поэтому даже малейшее улучшение считается.
Спасибо
5 ответов:
Простой способ-найти список наименьшей длины... чем использовать это с
set.intersection..., например:a = range(100) b = range(50) fst, snd = (a, b) if len(a) < len(b) else (b, a) len(set(fst).intersection(snd))
Я думаю, что такое выражение генератора будет быстрым
sum(1 for i in my_list if i in other_list)В противном случае пересечение
setпроисходит примерно с той же скоростью, что и пересечениеlen(set(my_list).intersection(other_list))
Из https://wiki.python.org/moin/TimeComplexity , пересечение множества для двух множеств
sиtимеет временную сложность:Среднее-O (min (len (s), len (t))
Худший - O(len (s) * len (t))
len([x for x in my_list if x in other_list])имеет сложность O (n^2), которая эквивалентна наихудшему случаю дляset.intersection().Если вы используете
set.intersection(), вам нужно сначала преобразовать один из списков в набор:Так что
len(set(my_list).intersection(other_list))должно в среднем будет быстрее, чем вложенный список понимание.
Можно попробовать использовать функцию
filter. Поскольку вы упомянули, что работаете с огромными списками,ifilterмодуляitertoolsбудет хорошим вариантом:from itertools import ifilter my_set = set(range(100)) other_set = set(range(50)) for item in ifilter(lambda x: x in other_set, my_set): print item
Идея состоит в том, чтобы сначала отсортировать два списка, а затем пересечь их, как мы хотим объединить их, чтобы найти элементы в первом списке, принадлежащие также второму списку. Таким образом, мы имеем алгоритм
O(n logn).def mycount(l, m): l.sort() m.sort() i, j, counter = 0, 0, 0 while i < len(l) and j < len(m): if l[i] == m[j]: counter += 1 i += 1 elif l[i] < m[j]: i += 1 else: j += 1 return counterИз локальных тестов это в 100 раз быстрее, чем
len([x for x in a if x in b])при работе со списками элементов10000.Редактировать:
Учитывая, что элементы списка уникальны, общие элементы будут иметь частоту два в объединении двух списков. Также они будем вместе, когда разберемся с этим союзом. Таким образом, справедливо и следующее:
def mycount(l, m): s = sorted(l + m) return sum(s[i] == s[i + 1] for i in xrange(len(s) - 1))Аналогично, мы можем использовать счетчик:
from collections import Counter def mycount(l, m): c = Counter(l) c.update(m) return sum(v == 2 for v in c.itervalues())
Comments