Возьмите пересечение произвольного числа списков в Python - PullRequest
4 голосов
/ 24 мая 2010

Предположим, у меня есть список списков элементов, которые все одинаковы (в этом примере я буду использовать int s)

[range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]

Каким был бы хороший и / или эффективный способ пересечения этих списков (чтобы вы могли получить каждый элемент в каждом из списков)? Для примера это будет:

[0, 12, 24, 36, 48, 60, 72, 84, 96]

Ответы [ 7 ]

7 голосов
/ 24 мая 2010

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

>>> s = set()
>>> s.add(4)
>>> s.add(5)
>>> s
set([4, 5])
>>> t = set([2, 4, 9])
>>> s.intersection(t)
set([4])

Для вашего примера, что-то вроде

>>> data = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
>>> sets = map(set, data)
>>> print set.intersection(*sets)
set([0, 96, 36, 72, 12, 48, 84, 24, 60])
4 голосов
/ 24 мая 2010

Я думаю, что встроенный модуль set должен добиться цели.

>>> elements = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
>>> sets = map(set, elements)
>>> result = list(reduce(lambda x, y: x & y, sets))
>>> print result
[0, 96, 36, 72, 12, 48, 84, 24, 60]
3 голосов
/ 24 мая 2010

Преобразуйте их в наборы и используйте метод set.intersection, сократив список наборов:

xs = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
reduce(set.intersection, [set(x) for x in xs])

reduce - это функциональное устройство программирования, которое выполняет итерацию для любой итерации и применяет функцию, предоставленную для первых двух элементов, затем к результату и следующему, а затем к результату , который и следующ и т. д.

1 голос
/ 24 мая 2010

Я собираюсь ответить на свой вопрос:

lists =  [range(100)[::4],range(100)[::3],range(100)[::2],range(100)[::1]]

out = set(lists[0])
for l in lists[1:]:
    out = set(l).intersection(out)

print out

или

print list(out)
0 голосов
/ 18 мая 2017

Вот одна строка с использованием старой доброй встроенной функции all():

list(num for num in data[0] 
     if all(num in range_ for range_ in data[1:]))

Интересно, что это (я думаю) более читабельно и быстрее, чем использование set для больших наборов данных.

0 голосов
/ 24 мая 2010
l = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
l = [set(i) for i in l]
intersect = l[0].intersection(l[1])
for i in l[2:]:
    intersect = intersect.intersection(i)
0 голосов
/ 24 мая 2010

Вы можете рассматривать их как наборы и использовать set.intersection():

lists = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
sets = [set(l) for l in lists]

isect = reduce(lambda x,y: x.intersection(y), sets)
...