Pythoniczny sposób tworzenia unii wszystkich wartości zawartych na wielu listach


84

Mam listę list:

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

Chcę spłaszczyć tę listę i usunąć wszystkie duplikaty; lub, innymi słowy, zastosuj operację set union:

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

Jaki jest najłatwiejszy sposób na zrobienie tego?

Odpowiedzi:


152

set.union robi co chcesz:

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

Możesz to również zrobić z więcej niż dwoma listami.


@sth, na przykład dzięki, ale kiedy go uruchamiam, pojawia się błąd: Traceback (ostatnie połączenie ostatnie): Plik "so_example.py", wiersz 33, w? results_union = set (). union (* result_lists) TypeError: union () przyjmuje dokładnie jeden argument (podane 3)
AJ.

1
@AJ: Zgodnie z dokumentacją ( docs.python.org/library/stdtypes.html#set.union ) union()obsługuje tylko wiele argumentów dla Pythona w wersji 2.6 lub nowszej. Wydaje się, że używasz wcześniejszej wersji, więc prawdopodobnie musisz użyć jawnej pętli: total = set(); for x in results_list: total.update(x) (s /; / \ n /)
sth

2
Możesz także zapisać tworzenie pustego zestawu, zmieniając drugą linię naresults_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'w Pythonie 3.6 co najmniej.
Paritosh Singh

1
Jeśli używasz set.union(*results_list), wiążesz deskryptor metody ręcznie, tj. Wysyłasz pierwszy element results_listjako „self”. Stwarza to pewne dziwne ograniczenia: 1. nie jest poprawnie typem duck (teraz pierwszy element musi być zestawem lub instancją podklasy set), oraz 2. suma pustego results_listbędzie błędem (niepoprawny wynik - powinien zwrócić pusty zestaw).
wim

12

Ponieważ wydaje się, że używasz Pythona 2.5 ( byłoby miło wspomnieć w swoim Q, jeśli potrzebujesz A dla wersji! = 2.6, przy okazji bieżącej wersji produkcyjnej ;-) i chcesz raczej listę niż zestaw jako wynik, polecam:

import itertools

...

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

itertools to ogólnie świetny sposób pracy z iteratorami (a więc z wieloma rodzajami sekwencji lub kolekcji) i serdecznie polecam zapoznanie się z nim. itertools.chainw szczególności jest udokumentowana tutaj .


+1 Doskonały przykład dobrego czasu na zanurzenie się we wspaniałym itertoolsopakowaniu.
gotgenes

@Alex dzięki ... zredagowałem moje pytanie, aby określić wersję i usunąć winy z siebie za to, że jestem tak opóźniony w wersjach :) Sprawię, że zajrzę do itertools, doceniam sugestię.
AJ.

@AJ, bez winy, w końcu wszyscy możemy cierpieć z powodu takich ograniczeń (ale pamiętaj, aby określić w przyszłych Qs! -); itertools.chainNawiasem mówiąc, działa dobrze również w Pythonie 2.4.
Alex Martelli

3

Możesz również podążać za tym stylem

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

Związki nie są obsługiwane przez listy, które są uporządkowane, ale są obsługiwane przez zestawy. Sprawdź set.union .


0

Użyłem poniższego, aby wykonać przecięcia, co pozwala uniknąć zestawów.

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

lub,

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

5
Dlaczego miałbyś w ogóle chcieć „uniknąć zestawów”? W tym celu są szybsze i wyraźniejsze. A twoje „x in a” wykonuje liniowe, brutalne przeszukiwanie listy za każdym razem, gdy je wykonujesz. Fuj.
Peter Hansen

zestawy wymagają rzucania typów, a prędkość liniowa nie jest zła, chyba że masz do czynienia z dużym N.
Bear

3
„Casting typu”? W Pythonie? Od kiedy? Zestawy są w zasadzie dyktowane tylko z kluczami i używają porównań hash i równości. Użycie „x in a” na liście powoduje również porównanie równości. O co chodzi z rzutowaniem czcionek?
Peter Hansen

0

ze zrozumieniem:

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

lub

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.