tags:

views:

1411

answers:

6

I have tried this on the python interpreter:

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

I think that I can't add the list to the set because there's no way python can tell If I have added the same list twice. Is there a workaround?

EDIT: I want to add the list itself, not its elements.

+15  A: 

You can't add a list to a set because lists are mutable, meaning that you can change the contents of the list after adding it to the set.

You can however add tuples to the set, because you cannot change the contents of a tuple:

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


Edit: some explanation: The documentation defines a set as an unordered collection of distinct hashable objects. The objects have to be hashable so that finding, adding and removing elements can be done faster than looking at each individual element every time you perform these operations. The specific algorithms used are explained in the Wikipedia article. Pythons hashing algorithms are explained on effbot.org and pythons __hash__ function in the python reference.

Some facts:

  • Set elements as well as dictionary keys have to be hashable
  • Some unhashable datatypes:
    • list: use tuple instead
    • set: use frozenset instead
    • dict: has no official counterpart, but there are some recipes
  • Object instances are hashable by default with each instance having a unique hash. You can override this behavior as explained in the python reference.
Otto Allmendinger
And if you ever want to add a set to a set, use frozenset.
FogleBird
[`collections.namedtuple`](http://docs.python.org/library/collections.html#collections.namedtuple) might be considered "official" counterpart of the `dict`.
SilentGhost
@FogleBird or the union operator: |=
Wahnfrieden
Well answered!
T Pops
@Wahnfrieden: that is adding the *contents* of a set, not the set itself.
Otto Allmendinger
Well answered. The tuple() function is also worth mentioning.
Adam Matan
+2  A: 
>>> a=set('abcde')
>>> l=['f','g']
>>> a|=set(l)
>>> a
set(['a', 'c', 'b', 'e', 'd', 'g', 'f'])

The union operator is much faster than add anyway.

edit: If you want the list itself and not its members, then you must use a tuple, unfortunately. Set members must be hashable.

Wahnfrieden
+3  A: 

list objects are unhashable. you might want to turn them in to tuples though.

SilentGhost
A: 

You'll want to use tuples, which are hashable (you can't hash a mutable object like a list).

>>> 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
Wow, we wrote almost exactly the same thing at the same time.
hughdbrown
+1  A: 

You want to add a tuple, not a 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')])

If you have a list, you can convert to the tuple, as shown above. A tuple is immutable, so it can be added to the set.

hughdbrown
you don't need `tuple(x for x in l)`, you can just do: `tuple(l)`
SilentGhost
Ah, right. I have list comprehension syntax stuck in my fingers.
hughdbrown
+1  A: 

Sets can't have mutable (changeable) elements/members. A list, being mutable, cannot be a member of a set.

As sets are mutable, you cannot have a set of sets! You can have a set of frozensets though.

(The same kind of "mutability requirement" applies to the keys of a dict.)

Other answers have already given you code, I hope this gives a bit of insight. I'm hoping Alex Martelli will answer with even more details.