2010-03-29 34 views
148

Tôi có một danh sách các bộ:Cách tốt nhất để tìm giao lộ của nhiều bộ?

setlist = [s1,s2,s3...] 

Tôi muốn s1 s2 ∩ ∩ s3 ...

tôi có thể viết một chức năng để làm điều đó bằng cách thực hiện một loạt các cặp s1.intersection(s2) vv

Có cách nào được đề xuất, tốt hơn hoặc được tích hợp sẵn không?

Trả lời

278

Từ Python phiên bản 2.6 trên bạn có thể sử dụng nhiều lập luận để set.intersection(), như

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

Nếu bộ đang ở trong một danh sách, điều này chuyển đến:

u = set.intersection(*setlist) 

nơi *a_listlist expansion

+0

Bạn có thể vui lòng giải thích hoặc chỉ cho tôi tài liệu liên quan về những gì '* setlist' có nghĩa là ở đây không? (Cụ thể, dấu hoa thị làm gì?) Cảm ơn! – PurpleVermont

+6

Đối với bất kỳ ai khác có thể có cùng câu hỏi với tôi, tôi đã tìm thấy câu trả lời ở đây: http://stackoverflow.com/questions/400739/what-does-asterisk-mean-in-python – PurpleVermont

10

Nếu bạn không có Python 2.6 hoặc cao hơn, người ta xoay sang viết một rõ ràng cho vòng lặp:

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

Bạn cũng có thể sử dụng reduce:

set_list = [set([1, 2]), set([1, 3]), set([1, 4])] 
print reduce(lambda s1, s2: s1 & s2, set_list) 
# Output: set([1]) 

Tuy nhiên, nhiều lập trình viên Python không thích nó, including Guido himself:

Khoảng 12 năm trước, Python aquired lambda, reduce(), fil ter() và map(), lịch sự của (tôi tin) một hacker Lisp đã bỏ lỡ chúng và gửi các bản vá lỗi làm việc. Nhưng, mặc dù giá trị PR, tôi nghĩ rằng các tính năng này nên được cắt từ Python 3000.

Vì vậy, bây giờ giảm(). Đây thực sự là điều tôi ghét nhất, bởi vì, ngoài một vài ví dụ liên quan đến + hoặc *, hầu như mỗi lần tôi thấy một cuộc gọi reduce() với một đối số hàm số không nhỏ, tôi cần lấy bút và giấy để sơ đồ những gì thực sự đang được đưa vào hàm đó trước khi tôi hiểu những gì giảm() là nghĩa vụ phải làm. Vì vậy, trong tâm trí của tôi, khả năng áp dụng của reduce() là khá nhiều giới hạn cho các nhà khai thác kết hợp, và trong tất cả các trường hợp khác nó tốt hơn để viết ra các vòng lặp tích lũy một cách rõ ràng.

+8

Lưu ý rằng Guido nói sử dụng 'reduce' là "giới hạn đối với các nhà khai thác kết hợp", mà là áp dụng trong trường hợp này. 'reduce' thường rất khó tìm ra, nhưng đối với' & 'không quá tệ. –

+0

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

+0

Kiểm tra https://www.python.org/doc/essays/list2str/ cho tối ưu hóa hữu ích liên quan đến giảm. Nó có thể nói chung được sử dụng khá độc đáo để xây dựng danh sách, bộ, dây vv Giá trị một cái nhìn cũng là https://github.com/EntilZha/PyFunctional – Andreas

41

Kể từ 2.6, set.intersection mất nhiều tùy ý có thể lặp lại.

>>> 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

Ở đây tôi đang cung cấp một chức năng chung cho ngã tư nhiều bộ cố gắng để tận dụng lợi thế của phương pháp tốt nhất có sẵn:

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 có thể không thích reduce, nhưng tôi loại ngây thơ của nó :)

+0

Bạn nên kiểm tra độ dài của ' sets' thay vì cố gắng truy cập 'sets [0]' và bắt 'IndexError'. – bfontaine

+0

Đây không phải là một kiểm tra đơn giản; 'a_set' được sử dụng ở lần trả cuối cùng. – tzot

+0

Bạn không thể làm 'return reduce (sets [0], sets [1:]) nếu các tập hợp khác được đặt()'? – bfontaine

11

Rõ ràng set.intersection là những gì bạn muốn ở đây, nhưng trong trường hợp bạn cần tổng quát "tổng hợp tất cả những điều này", "lấy sản phẩm của tất cả các", "lấy xor của tất cả những thứ này", những gì bạn đang tìm kiếm là reduce f bôi:

from operator import and_ 
from functools import reduce 
print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3} 

hoặc

print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3} 
Các vấn đề liên quan