user118662
user118662

Reputation: 2741

Python creating a dictionary of lists

I want to create a dictionary whose values are lists. For example:

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

If I do:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d[j].append(i)

I get a KeyError, because d[...] isn't a list. In this case, I can add the following code after the assignment of a to initialize the dictionary.

for x in range(1, 4):
    d[x] = list()

Is there a better way to do this? Lets say I don't know the keys I am going to need until I am in the second for loop. For example:

class relation:
    scope_list = list()
...
d = dict()
for relation in relation_list:
    for scope_item in relation.scope_list:
        d[scope_item].append(relation)

An alternative would then be replacing

d[scope_item].append(relation)

with

if d.has_key(scope_item):
    d[scope_item].append(relation)
else:
    d[scope_item] = [relation,]

What is the best way to handle this? Ideally, appending would "just work". Is there some way to express that I want a dictionary of empty lists, even if I don't know every key when I first create the list?

Upvotes: 248

Views: 626512

Answers (7)

Moti Zamir
Moti Zamir

Reputation: 1

If you create it from a list, you can also use dict comprehension with a list comprehension within it:

dict_of_list_values = {len(k): [name for name in names if len(name) == len(k)] for k in names}

(I used a list of names for this example)

Upvotes: 0

RichieHindle
RichieHindle

Reputation: 281835

You can use setdefault:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d.setdefault(j, []).append(i)

print d  # prints {1: ['1'], 2: ['1', '2'], 3: ['2']}

The rather oddly-named setdefault function says "Get the value with this key, or if that key isn't there, add this value and then return it."

As others have rightly pointed out, defaultdict is a better and more modern choice. setdefault is still useful in older versions of Python (prior to 2.5).

Upvotes: 42

mechanical_meat
mechanical_meat

Reputation: 169494

You can use defaultdict:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = ['1', '2']
>>> for i in a:
...   for j in range(int(i), int(i) + 2):
...     d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]

Upvotes: 316

Henning Lee
Henning Lee

Reputation: 584

easy way is:

a = [1,2]
d = {}
for i in a:
  d[i]=[i, ]

print(d)
{'1': [1, ], '2':[2, ]}

Upvotes: 2

john k
john k

Reputation: 6614

Personally, I just use JSON to convert things to strings and back. Strings I understand.

import json
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
mydict = {}
hash = json.dumps(s)
mydict[hash] = "whatever"
print mydict
#{'[["yellow", 1], ["blue", 2], ["yellow", 3], ["blue", 4], ["red", 1]]': 'whatever'}

Upvotes: 3

spiffyman
spiffyman

Reputation: 624

Your question has already been answered, but IIRC you can replace lines like:

if d.has_key(scope_item):

with:

if scope_item in d:

That is, d references d.keys() in that construction. Sometimes defaultdict isn't the best option (for example, if you want to execute multiple lines of code after the else associated with the above if), and I find the in syntax easier to read.

Upvotes: 2

Nadia Alramli
Nadia Alramli

Reputation: 115011

You can build it with list comprehension like this:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2'])
{'1': [1, 2], '2': [2, 3]}

And for the second part of your question use defaultdict

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

Upvotes: 61

Related Questions