У меня есть список наборов:
setlist = [s1,s2,s3...]
Я хочу s1 ∩ s2 ∩ s3...
Я могу написать функцию, чтобы сделать это, выполнив ряд попарно s1.intersection(s2)
и т.д.
Есть ли рекомендуемый, лучший или встроенный способ?
У меня есть список наборов:
setlist = [s1,s2,s3...]
Я хочу s1 ∩ s2 ∩ s3...
Я могу написать функцию, чтобы сделать это, выполнив ряд попарно s1.intersection(s2)
и т.д.
Есть ли рекомендуемый, лучший или встроенный способ?
В версии Python версии 2.6 вы можете использовать несколько аргументов для set.intersection()
, например
u = set.intersection(s1, s2, s3)
Если набор находится в списке, это означает:
u = set.intersection(*setlist)
где *a_list
- расширение списка
Начиная с 2.6, set.intersection
принимает произвольно много итераций.
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s3 = set([2, 4, 6])
>>> s1 & s2 & s3
set([2])
>>> s1.intersection(s2, s3)
set([2])
>>> sets = [s1, s2, s3]
>>> set.intersection(*sets)
set([2])
Если у вас нет Python 2.6 или выше, альтернативой является запись явного цикла for:
def set_list_intersection(set_list):
if not set_list:
return set()
result = set_list[0]
for s in set_list[1:]:
result &= s
return result
set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print set_list_intersection(set_list)
# Output: set([1])
Вы также можете использовать reduce
:
set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print reduce(lambda s1, s2: s1 & s2, set_list)
# Output: set([1])
Однако многим программистам на Python это не нравится, включая самого Guido:
Около 12 лет назад Python приобрел lambda, reduce(), filter() и map(), любезно предоставленный хакером Lisp, который пропустил их и представил рабочие исправления. Но, несмотря на ценность PR, я думаю, что эти функции должны быть отключены от Python 3000.
Итак, теперь сведем(). Это на самом деле тот, которого я всегда ненавидел больше всего, потому что, помимо нескольких примеров с участием + или *, почти каждый раз, когда я вижу вызов reduce() с нетривиальным аргументом функции, мне нужно захватить ручку и бумагу диаграммы, которые фактически подаются в эту функцию, прежде чем я пойму, что должен делать метод reduce(). Поэтому, по моему мнению, применимость reduce() в значительной степени ограничена ассоциативными операторами, и во всех остальных случаях лучше написать цикл накопления явно.
Ясно, что set.intersection
- это то, что вы хотите здесь, но в случае, если вам понадобится обобщение "взять сумму всех этих", "взять произведение всех этих", "взять все эти", что вы ищете функцию reduce
:
from operator import and_
from functools import reduce
print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
или
print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
Здесь я предлагаю общую функцию для множественного пересечения множеств, пытаясь воспользоваться лучшим доступным способом:
def multiple_set_intersection(*sets):
"""Return multiple set intersection."""
try:
return set.intersection(*sets)
except TypeError: # this is Python < 2.6 or no arguments
pass
try: a_set= sets[0]
except IndexError: # no arguments
return set() # return empty set
return reduce(a_set.intersection, sets[1:])
Гвидо может не понравиться reduce
, но я его люблю:)