Додати список для встановлення?


242

Тестований на інтерпретаторі 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

Я думаю, що я не можу додати список до набору, тому що Python не може сказати, якщо я два рази додав той самий список. Чи існує рішення?

EDIT: Я хочу додати сам список, а не його елементи.


2
Ви хочете додати список до набору чи елементів у списку?
pkit

Сам список - я хочу мати набір списків.
Адам Матан

Здається, найкраще відповідь є заниженою, пропонуючи використовувати aSet.add (id (lst)) перед тим, як додати lst до якогось списку / черги / тощо, щоб бути впевненим, що ви це зробили. Вам слід переглянути прийняту відповідь.
Рустам А.

Відповіді:


187

Ви не можете додати список до набору, оскільки списки можуть змінюватися, це означає, що ви можете змінити вміст списку після додавання його до набору.

Однак ви можете додати кортежі до набору, оскільки ви не можете змінити вміст кортежу:

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

Редагувати : деяке пояснення: Документація визначає setяк не упорядковану колекцію різних об'єктів, що змішуються. Об'єкти повинні бути доступними, щоб знайти, додавати та вилучати елементи можна швидше, ніж переглядати кожен окремий елемент кожного разу, коли ви виконуєте ці операції. Конкретні алгоритми, що використовуються, пояснюються у статті Вікіпедії . Алгоритми хешування хитов пояснюються на effbot.org, а пітони __hash__функціонують у довідці python .

Деякі факти:

  • Набір елементів , а також клавіші словника повинні бути перебірливими
  • Деякі типи даних:
    • list: використовувати tupleзамість цього
    • set: використовувати frozensetзамість цього
    • dict: не має офіційного аналога, але є деякі рецепти
  • Екземпляри об'єктів за замовчуванням є хешируемими, кожен з яких має унікальний хеш. Ви можете змінити таку поведінку, як пояснено в довідці python.

6
Якщо ви хочете додати набір до набору, використовуйте заморожений набір.
FogleBird

4
collections.namedtupleможе вважатися "офіційним" аналогом dict.
SilentGhost

1
@Wahnfrieden: це додавання вмісту набору, а не самого набору.
Otto Allmendinger

@aehlke: Ні, це додає елементи множини до першого набору, але ми говоримо про додавання набору як елемента першого набору.
Джефф Лірман

578

Використовуйте set.update()або|=

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

редагувати: Якщо ви хочете додати сам список, а не його членів, тоді, на жаль, ви повинні використовувати кортеж. Набір членів повинен бути хешируемым .


set.update () додає список до набору, правильно? для чого дорівнює оператор труби?
FistOfFury

Щодо наборів, |оператор реалізує задану операцію об'єднання . І |=оператор, і set.update()метод застосовують цю операцію на місці і фактично є синонімом. Отже, set_a |= set_bможе вважатися синтаксичним цукром для обох set_a.update(set_b) і set_a = set_a | set_b (за винятком того, що в останньому випадку один і той же set_aоб'єкт повторно використовується, а не перепризначається). </ahem>
Сесіль Карі

76

Щоб додати елементи списку до набору , використовуйтеupdate

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

s.update (t): повернути набір s з елементами, доданими з t

Напр

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

Якщо ви хочете додати весь набір як єдиний елемент до набору, ви не можете, оскільки списки не підлягають перегляду. Ви можете замість цього додати кортеж, наприклад s.add(tuple(l)). Дивіться також TypeError: unhashable type: 'list' при використанні вбудованої функції набору для отримання додаткової інформації про це.


40

Сподіваємось, це допомагає:

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

15

Зверніть увагу на функцію set.update(). Документація говорить:

Оновіть набір об'єднанням себе та інших.


5
Це не дає відповіді на запитання (оскільки ОП хоче додати список до набору), але мені потрібна була відповідь, коли Google привів мене сюди :-)
Tom Stratton

1
Ну, здається, що найвідповідніша відповідь на питання до мене ... наприклад, якщо b = set ([1]), b.update ([7,25]) дасть b таке значення: set ([ 1, 25, 7]) ---> Хіба це не те, що ми шукаємо тут?
Луї ЛК

8

об'єкти списку непридатні . ви, можливо, захочете перетворити їх на кортежі.


5

Набори не можуть мати змінних (змінних) елементів / елементів. Список, який можна змінити, не може бути членом набору.

Оскільки набори є змінними, ви не можете мати набір наборів! Ти можеш мати набір фрозенсетів.

(Така ж "вимога щодо змінності" застосовується до клавіш диктату.)

Інші відповіді вам уже дали код, сподіваюся, це дає трохи розуміння. Я сподіваюся, що Алекс Мартеллі відповість ще більше деталями.


4

Ви хочете додати кортеж, а не список:

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

Якщо у вас є список, ви можете перетворити в кортеж, як показано вище. Кортеж незмінний, тому його можна додати до набору.


4

Я виявив, що мені потрібно зробити щось подібне сьогодні. Алгоритм знав, коли він створює новий список, який потрібно додати до набору, але не коли він закінчив би працювати зі списком.

У будь-якому разі, поведінку, яку я хотів, було idскоріше використовувати, а не використовувати hash. Як такого я знайшов mydict[id(mylist)] = mylistзамість того, myset.add(mylist)щоб пропонувати поведінку, яку я хотів.


3

Ви хочете використовувати кортежі, які є хешируемими (ви не можете хеш-змінний об'єкт, як список).

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

2

Ось як я зазвичай це роблю:

def add_list_to_set(my_list, my_set):
    [my_set.add(each) for each in my_list]
return my_set

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.