2010-03-29 3 views

ответ

278

С Python версии 2.6 на вы можете использовать несколько аргументов, чтобы set.intersection(), как

u = set.intersection(s1, s2, s3) 

Если наборы находятся в списке, это приводит к:

u = set.intersection(*setlist) 

где *a_list является list expansion

+0

Не могли бы вы объяснить или указать мне соответствующую документацию, что означает '* setlist'? (В частности, что делает звездочка?) Спасибо! – PurpleVermont

+6

Для всех, у кого может быть такой же вопрос, как я, я нашел ответ здесь: http://stackoverflow.com/questions/400739/what-does-asterisk-mean-in-python – PurpleVermont

10

Если у вас нет Python 2.6 или выше, альтернатива, чтобы написать явный цикл:

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 не нравится, including Guido himself:

Около 12 лет назад Python приобрел лямбда, уменьшил() , filter() и map(), любезно предоставленный (я считаю) хакер Lisp, который пропустил их и представил рабочие исправления. Но, несмотря на ценность PR, я думаю, что эти функции должны быть вырезаны из Python 3000.

Теперь теперь уменьшите(). Это на самом деле тот, которого я всегда ненавидел больше всего, потому что, помимо нескольких примеров с участием + или *, почти каждый раз, когда я вижу вызов reduce() с нетривиальным аргументом функции, мне нужно захватить ручку и бумагу диаграмму, что на самом деле подается в эту функцию, прежде чем я пойму, что должен делать метод reduce(). Поэтому, на мой взгляд, применимость reduce() в значительной степени ограничена ассоциативными операторами, и во всех остальных случаях лучше написать цикл накопления явно.

+8

Обратите внимание, что Гвидо говорит с помощью 'reduce' является "ограничивается ассоциативных операторов", который применим в данном случае. 'reduce' очень часто трудно понять, но для' & 'не так уж плохо. –

+0

['set_list and reduce (set.intersection, set_list)'] (http://stackoverflow.com/a/1404146/4279) – jfs

+0

Проверьте https://www.python.org/doc/essays/list2str/ для полезные оптимизации с уменьшением. В общем случае можно использовать довольно хорошо для создания списков, наборов, строк и т. Д. Стоит также взглянуть на https://github.com/EntilZha/PyFunctional – Andreas

41

Начиная с версии 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]) 
1

Здесь я предлагаю обобщенную функцию для многократного пересечения множества пытается воспользоваться наилучшим доступным способом:

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:]) 

Guido может не любить reduce, но я вроде люблю его :)

+0

Вы должны проверить длину ' sets' вместо того, чтобы пытаться получить доступ к 'sets [0]' и ловить 'IndexError'. – bfontaine

+0

Это не простая проверка; 'a_set' используется при окончательном возврате. – tzot

+0

Не можете ли вы сделать return return (устанавливает [0], устанавливает [1:]), если устанавливает else set() '? – bfontaine

11

Ясно, что 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} 
Смежные вопросы