Dodaj listę do ustawienia?

242

Testowane na interprecie języka Python 2.6:

>>> a=set('abcde')
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> l=['f','g']
>>> l
['f', 'g']
>>> a.add(l)
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    a.add(l)
TypeError: list objects are unhashable

Myślę, że nie mogę dodać listy do zestawu, ponieważ nie ma możliwości, aby Python mógł stwierdzić, czy dodałem tę samą listę dwa razy. Czy jest w pobliżu praca?

EDYCJA: Chcę dodać samą listę, a nie jej elementy.

Adam Matan
źródło
2
Czy chcesz dodać listę do zestawu lub elementów na liście?
pkit
Sama lista - chcę mieć zestaw list.
Adam Matan,
Wydaje się, że najlepiej pasującą odpowiedzią jest niedoceniana, sugerująca użycie aSet.add (id (lst)) przed dodaniem samego lst do jakiejś listy / kolejki / itp., Aby mieć pewność, że to zrobiłeś. Powinieneś ponownie rozważyć zaakceptowaną odpowiedź.
Rustam A.

Odpowiedzi:

187

Nie można dodać listy do zestawu, ponieważ listy można modyfikować, co oznacza, że ​​można zmienić zawartość listy po dodaniu jej do zestawu.

Możesz jednak dodać krotki do zestawu, ponieważ nie możesz zmienić zawartości krotki:

>>> a.add(('f', 'g'))
>>> print a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])

Edycja : niektóre wyjaśnienia: Dokumentacja definiuje setjako nieuporządkowany zbiór różnych obiektów możliwych do skrótu. Obiekty muszą być haszowalne, aby wyszukiwanie, dodawanie i usuwanie elementów odbywało się szybciej niż patrzenie na każdy element za każdym razem, gdy wykonujesz te operacje. Konkretne zastosowane algorytmy wyjaśniono w artykule w Wikipedii . Algorytmy mieszające Pythona są wyjaśnione na stronie effbot.org, a __hash__funkcja pytonów w odnośniku do Pythona .

Kilka faktów:

  • Elementy zestawu, a także klawisze słownika muszą być haszowalne
  • Niektóre typy danych nie do opanowania:
    • list: użyj tuplezamiast tego
    • set: użyj frozensetzamiast tego
    • dict: nie ma oficjalnego odpowiednika, ale istnieją pewne przepisy
  • Instancje obiektów są domyślnie mieszalne, a każde wystąpienie ma unikalny skrót. Możesz zastąpić to zachowanie, jak wyjaśniono w dokumentacji Pythona.
Otto Allmendinger
źródło
6
A jeśli kiedykolwiek chcesz dodać zestaw do zestawu, użyj frozenset.
FogleBird,
4
collections.namedtuplemoże być uważany za „oficjalny” odpowiednik dict.
SilentGhost,
1
@Wahnfrieden: to dodaje zawartość zestawu, a nie sam zestaw.
Otto Allmendinger,
@aehlke: Nie, to dodaje elementy zestawu do pierwszego zestawu, ale mówimy o dodaniu zestawu jako elementu pierwszego zestawu.
Jeff Learman
578

Użyj set.update()lub|=

>>> a = set('abc')
>>> l = ['d', 'e']
>>> a.update(l)
>>> a
{'e', 'b', 'c', 'd', 'a'}

>>> l = ['f', 'g']
>>> a |= set(l)
>>> a
{'e', 'b', 'f', 'c', 'd', 'g', 'a'}

edycja: Jeśli chcesz dodać samą listę, a nie jej członków, musisz niestety użyć krotki. Członkowie zestawu muszą mieć funkcję skrótu .

aehlke
źródło
set.update () dodaje listę do zestawu, prawda? do czego służy rura równa się operatorowi?
FistOfFury
W odniesieniu do zestawów |operator realizuje operację łączenia zestawów . Zarówno |=operator, jak i set.update()metoda stosują tę operację w miejscu i są skutecznie synonimami. Tak więc, set_a |= set_bmożna uznać zarówno za cukier syntaktyczny set_a.update(set_b) i set_a = set_a | set_b (chyba że w tym ostatnim przypadku, ten sam set_aobiekt jest wykorzystywany zamiast przeniesiony). </ahem>
Cecil Curry
76

Aby dodać elementy listy do zestawu , użyjupdate

Od https://docs.python.org/2/library/sets.html

s.update (t): zwraca zestaw s z elementami dodanymi z t

Na przykład

>>> s = set([1, 2])
>>> l = [3, 4]
>>> s.update(l)
>>> s
{1, 2, 3, 4}

Jeśli zamiast tego chcesz dodać całą listę jako pojedynczy element do zestawu, nie możesz tego zrobić, ponieważ listy nie są mieszalne. Zamiast tego możesz dodać krotkę, np s.add(tuple(l)). Zobacz także TypeError: unhashable type: 'list', gdy używasz wbudowanej funkcji set, aby uzyskać więcej informacji na ten temat.

JDiMatteo
źródło
40

Mam nadzieję, że to pomaga:

>>> seta = set('1234')
>>> listb = ['a','b','c']
>>> seta.union(listb)
set(['a', 'c', 'b', '1', '3', '2', '4'])
>>> seta
set(['1', '3', '2', '4'])
>>> seta = seta.union(listb)
>>> seta
set(['a', 'c', 'b', '1', '3', '2', '4'])
alvas
źródło
15

Proszę zwrócić uwagę na funkcję set.update(). Dokumentacja mówi:

Zaktualizuj zestaw, łącząc siebie i innych.

jajo
źródło
5
To nie odpowiada na pytanie (ponieważ OP chce dodać samą listę do zestawu), ale była to odpowiedź, której potrzebowałem, kiedy Google mnie tu przyprowadził :-)
Tom Stratton
1
Cóż, wydaje mi się, że jest to najbardziej odpowiednia odpowiedź na pytanie ... na przykład, jeśli b = set ([1]), b. Aktualizacja ([7,25]) da b następującą wartość: set ([ 1, 25, 7]) ---> Czy nie tego tu szukamy?
Louis LC,
8

obiektów listy nie da się zhashować . jednak możesz je zamienić na krotki.

SilentGhost
źródło
5

Zestawy nie mogą mieć zmiennych / zmiennych elementów / elementów. Zmodyfikowana lista nie może być członkiem zestawu.

Ponieważ zestawy są zmienne, nie możesz mieć zestawu zestawów! Możesz jednak mieć zestaw frozensetów.

(Ten sam rodzaj „wymogu zmienności” dotyczy kluczy dykta).

Inne odpowiedzi już dały ci kod, mam nadzieję, że daje to trochę wglądu. Mam nadzieję, że Alex Martelli odpowie jeszcze bardziej szczegółami.

użytkownik135331
źródło
4

Chcesz dodać krotkę, a nie listę:

>>> a=set('abcde')
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> l=['f','g']
>>> l
['f', 'g']
>>> t = tuple(l)
>>> t
('f', 'g')
>>> a.add(t)
>>> a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])

Jeśli masz listę, możesz przekonwertować na krotkę, jak pokazano powyżej. Krotka jest niezmienna, więc można ją dodać do zestawu.

Hughdbrown
źródło
4

Odkryłem, że muszę dziś zrobić coś podobnego. Algorytm wiedział, kiedy tworzy nową listę, którą należy dodać do zestawu, ale nie wie, kiedy przestanie działać na liście.

W każdym razie zachowanie, którego chciałem, było idraczej zgodne z zestawem hash. Jako taki znalazłem mydict[id(mylist)] = mylistzamiast myset.add(mylist)oferować zachowanie, które chciałem.

Wydmy
źródło
3

Będziesz chciał użyć krotek, które są haszowalne (nie możesz haszować zmiennego obiektu, takiego jak lista).

>>> a = set("abcde")
>>> a
set(['a', 'c', 'b', 'e', 'd'])
>>> t = ('f', 'g')
>>> a.add(t)
>>> a
set(['a', 'c', 'b', 'e', 'd', ('f', 'g')])
Noah
źródło
2

Oto jak zwykle to robię:

def add_list_to_set(my_list, my_set):
    [my_set.add(each) for each in my_list]
return my_set
kashif
źródło
-4

To powinno zrobić:

set(tuple(i) for i in L)
WQS
źródło