Cách Pythonic để tạo liên hiệp tất cả các giá trị có trong nhiều danh sách


84

Tôi có một danh sách các danh sách:

lists = [[1,4,3,2,4], [4,5]]

Tôi muốn san bằng danh sách này và loại bỏ tất cả các bản sao; hoặc, nói cách khác, áp dụng một hoạt động liên hiệp đã định:

desired_result = [1, 2, 3, 4, 5]

Cách dễ nhất để làm điều này là gì?

Câu trả lời:


152

set.union làm những gì bạn muốn:

>>> results_list = [[1,2,3], [1,2,4]]
>>> results_union = set().union(*results_list)
>>> print(results_union)
set([1, 2, 3, 4])

Bạn cũng có thể làm điều này với nhiều hơn hai danh sách.


@sth, cảm ơn chẳng hạn, nhưng khi tôi chạy nó, tôi gặp lỗi: Traceback (lần gọi gần đây nhất): Tệp "so_example.py", dòng 33, trong? results_union = set (). union (* result_lists) LoạiError: union () nhận đúng một đối số (3 cho trước)
AJ.

1
@AJ: Theo documention ( docs.python.org/library/stdtypes.html#set.union ) union()chỉ hỗ trợ nhiều đối số cho Python phiên bản 2.6 trở lên. Bạn dường như sử dụng một phiên bản trước đó, vì vậy bạn có thể phải sử dụng một vòng lặp rõ ràng: total = set(); for x in results_list: total.update(x) (s /; / \ n /)
sth

2
Bạn cũng có thể lưu tạo một tập hợp trống bằng cách thay đổi dòng thứ 2 thànhresults_union = set.union(*(set(el) for el in results_list))
Noel Evans

1
@ Jean-FrançoisFabre TypeError: descriptor 'union' requires a 'set' object but received a 'list'trong python 3.6 ít nhất.
Paritosh Singh

1
Nếu bạn sử dụng, set.union(*results_list)bạn đang liên kết trình mô tả phương thức theo cách thủ công, tức là gửi phần tử đầu tiên results_listlà "self". Điều này gây ra một số hạn chế kỳ lạ: 1. không đúng kiểu vịt (bây giờ phần tử đầu tiên phải là một tập hợp hoặc thể hiện của một lớp con tập hợp), và 2. liên hợp của một sản phẩm trống results_listsẽ là một lỗi (kết quả không chính xác - nên trả về trống bộ).
wim

12

Vì bạn dường như đang sử dụng Python 2.5 ( sẽ rất vui nếu bạn đề cập trong phần Q của bạn nếu bạn cần điểm A cho các phiên bản! = 2.6, phiên bản sản xuất hiện tại ;-) và muốn có một danh sách hơn là một bộ kết quả, tôi khuyên bạn nên:

import itertools

...

return list(set(itertools.chain(*result_list)))

itertools nói chung là một cách tuyệt vời để làm việc với trình vòng lặp (và như vậy với nhiều loại trình tự hoặc tập hợp) và tôi chân thành khuyên bạn nên làm quen với nó. itertools.chain, cụ thể, được ghi lại ở đây .


+1 Một ví dụ hoàn hảo về thời điểm tốt để nhúng vào itertoolsgói tuyệt vời .
gotgenes

@Alex cảm ơn ... đã chỉnh sửa câu hỏi của tôi để chỉ định phiên bản và loại bỏ trách nhiệm từ bản thân tôi vì đã quá chậm trong các phiên bản :) Tôi sẽ làm cho nó một điểm để xem xét itertools, đánh giá cao đề xuất.
AJ.

@AJ, không có gì đáng trách, sau cùng thì tất cả chúng ta đều có thể chịu đựng những ràng buộc như vậy (nhưng hãy nhớ nêu rõ trong Qs trong tương lai! -); itertools.chainNhân tiện, hoạt động tốt trong Python 2.4.
Alex Martelli

3

Bạn cũng có thể làm theo phong cách này

In [12]: a = ['Orange and Banana', 'Orange Banana']
In [13]: b = ['Grapes', 'Orange Banana']
In [14]: c = ['Foobanana', 'Orange and Banana']

In [20]: list(set(a) | set(b) | set(c))
Out[20]: ['Orange and Banana', 'Foobanana', 'Orange Banana', 'Grapes']

In [21]: list(set(a) & set(b) | set(c))
Out[21]: ['Orange and Banana', 'Foobanana', 'Orange Banana']    

1

Các công đoàn không được hỗ trợ bởi danh sách, theo thứ tự, nhưng được hỗ trợ bởi tập hợp. Kiểm tra set.union .


0

Tôi đã sử dụng những điều sau đây để thực hiện các giao lộ, điều này tránh sự cần thiết của các bộ.

a, b= [[1,2,3], [1,2]]
s = filter( lambda x: x in b, a)

hoặc là,

s = [ x for x in b if x in a ]

5
Tại sao bạn thậm chí muốn "tránh sự cần thiết của bộ"? Chúng nhanh hơn và rõ ràng hơn cho mục đích này. Và "x trong a" của bạn thực hiện tìm kiếm tuyến tính, bạo lực qua danh sách mỗi khi bạn thực hiện nó. Kinh quá.
Peter Hansen

bộ yêu cầu loại đúc, và tốc độ tuyến tính không phải là xấu, trừ khi bạn đang đối phó với một N. lớn
Gấu

3
"Kiểu đúc"? Trong Python? Kể từ khi? Về cơ bản, các tập hợp chỉ có các phím và chúng sử dụng phép so sánh hàm băm và bình đẳng. Sử dụng "x trong a" trên danh sách cũng thực hiện so sánh bình đẳng. Tất cả những điều này về kiểu đúc là gì?
Peter Hansen

0

theo cách hiểu:

[*{ j for i in lists for j in i }]

hoặc là

[*functools.reduce(lambda x,y: {*x, *y}, lists)]

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.