14

I would like to create a dictionary which is indexed by lists. For instance, my dictionary should look like:

D = {[1,2,3]:1, [2,3]:3}

Anyone know how to do this? If I just type D([1,2,3]) = 1 it returns an error.

Mike Graham
  • 73,987
  • 14
  • 101
  • 130
Chris
  • 171
  • 1
  • 6

3 Answers3

20

dict keys must be hashable, which lists are not becase they are mutable. You can change a list after you make it. Think of how tricky it would be to try to keep a dict when the data used as keys changes; it doesn't make any sense. Imagine this scenario

>>> foo = [1, 2]
>>> bar = {foo: 3}
>>> foo.append(4)

and you will see why Python does not try to support lists as keys.

The most obvious solution is to use tuples instead of lists as keys.

>>> d = {[1, 2, 3]: 1, [2, 3]: 3}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> d = {(1, 2, 3): 1, (2, 3): 3}
>>> d
{(2, 3): 3, (1, 2, 3): 1}
>>> d[2, 3]
3
Mike Graham
  • 73,987
  • 14
  • 101
  • 130
  • You mean dictionary keys, not tuple keys, in the first sentence. – Thomas Wouters Apr 19 '10 at 22:11
  • 1
    "try to keep a dict" => "try to keep a dict valid" –  Apr 19 '10 at 22:13
  • Just remember: Python doesn't know the difference between (1, 2) and (2, 1) when hashed... I had to create a class that can do this: https://gist.github.com/rjurney/d7913221dd38bee9708716f50c3c002e – rjurney Jun 28 '16 at 19:07
  • @rjurney I think you're a little confused. What do you mean "Python doesn't know the difference between (1, 2) and (2, 1) when hashed"? (BTW, your class claims to take sets but isn't at all sensible for sets.) – Mike Graham Jun 29 '16 at 02:10
  • @rjurney - I'm getting a key error when I run `d={(1, 2): 3}; print(d[(2, 1)])` on both 2.7.6 and 3.4. You should probably check it again. – rohithpr Sep 05 '16 at 11:02
  • @rjurney: Your point is true for sets (where (2,1) and (1,2) specify the same set). It's not true for tuples: `print hash((1,2)), hash((2,1))` yields `3713081631934410656 3713082714465905806` – Jeff Learman Jun 27 '18 at 20:36
  • Note that it's possible in Python to create a class whose objects are mutable but are hashable. It's a *very bad idea* and breaks underlying assumptions, though, so don't do it! See https://www.asmeurer.com/blog/posts/what-happens-when-you-mess-with-hashing-in-python – Jeff Learman Jun 27 '18 at 20:52
  • @MikeGraham thanks for the nice examples. – simhumileco Feb 21 '19 at 23:06
2

Dictionary keys can be only hashable objects. If you want the content of a list as a key you can convert the list to a tuple.

>>>d={}
>>>a = tuple((1,2))
>>>a
(1, 2)
>>>d[a] = 3
>>>print d
{(1, 2): 3}
joaquin
  • 82,968
  • 29
  • 138
  • 152
  • 3
    Keys must be *hashable*, not necessarily *immutable*. You can have mutable values that are hashable (although it's rarely useful) and immutable values that are not hashable (for example, tuples that contain unhashable values.) – Thomas Wouters Apr 19 '10 at 22:12
  • Thanks for the comment, though was the same thing... could you give an example of mutable and hashable? – joaquin Apr 19 '10 at 22:17
  • 4
    For an object to be sanely hashable, the answers it gives when you take its hash and do an equality comparison should never change. The actual object may be able to change in other ways. For example, if I had a class `Person` for defining persons, I may be able to use identity comparison for finding if two `Person` objects are equal no matter if I change things about a `Person`, like their age or address. If the mutability doesn't affect the calculation of equality and hash, it does not keep an object from being hashable. – Mike Graham Apr 19 '10 at 22:37
  • @Mike, Thanks for the answer, I just wrote the same question as a new SO question. – joaquin Apr 19 '10 at 22:41
1
d = {repr([1,2,3]): 'value'}

{'[1, 2, 3]': 'value'}

As explained by others (see also here), you cannot use a list directly. You can however use its string representation instead if you really want to use your list.

Community
  • 1
  • 1
Remi
  • 20,619
  • 8
  • 57
  • 41