У меня есть список наборов:
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
это расширение списка
Обратите внимание, что set.intersection
это не статический метод, но он использует функциональную нотацию для применения пересечения первого набора с остальной частью списка. Так что, если список аргументов пуст, это не удастся.
Очевидно, set.intersection
это то, что вы хотите здесь, но в случае, если вам когда-либо понадобится обобщение «взять сумму всех этих», «взять произведение всех этих», «взять xor всех этих», то, что вы ищете, так это 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}
Если у вас нет 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 это не нравится, включая самого Гвидо :
Около 12 лет назад Python приобрел лямбду, lower (), filter () и map (), любезно (я полагаю) хакера Lisp, который пропустил их и представил рабочие исправления. Но, несмотря на ценность PR, я думаю, что эти функции должны быть вырезаны из Python 3000.
Так что теперь уменьшаем (). Это на самом деле тот, который я всегда ненавидел больше всего, потому что, за исключением нескольких примеров, включающих + или *, почти каждый раз, когда я вижу вызову redu () с нетривиальным аргументом функции, мне нужно взять ручку и бумагу, чтобы представьте диаграмму, что на самом деле подается в эту функцию, прежде чем я пойму, что должен делать redu (). Поэтому, на мой взгляд, применимость метода limit () в значительной степени ограничена ассоциативными операторами, и во всех других случаях лучше явно выписать цикл накопления.
result
он пуст.
Здесь я предлагаю универсальную функцию для пересечения множества множеств, пытаясь воспользоваться лучшим из доступных методов:
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
, но мне это нравится :)
sets
вместо того, чтобы пытаться получить sets[0]
и поймать IndexError
.
a_set
используется при окончательном возврате.
return reduce(sets[0], sets[1:]) if sets else set()
?
try
/ except
, если это возможно. Это запах кода, он неэффективен и может скрывать другие проблемы.
reduce
«ограничено ассоциативными операторами», что применимо в этом случае.reduce
очень часто трудно понять, но&
не все так плохо.