How to Initialize a Dictionary of Distinct Empty Lists in Python

How can I initialize a dictionary of distinct empty lists in Python?

Passing [] as second argument to dict.fromkeys() gives a rather useless result – all values in the dictionary will be the same list object.

In Python 2.7 or above, you can use a dicitonary comprehension instead:

data = {k: [] for k in range(2)}

In earlier versions of Python, you can use

data = dict((k, []) for k in range(2))

Initialise a dict of empty lists

How can I know this would be the behaviour

The Python documentation says it and warns you:

classmethod fromkeys(iterable[, value])

Create a new dictionary with keys from iterable and values set to value.

fromkeys() is a class method that returns a new dictionary. value defaults to None. All of the values refer to just a single instance,
so it generally doesn’t make sense for value to be a mutable object
such as an empty list
. To get distinct values, use a dict
comprehension instead.

Initialize a dictionary where each item is a list of empty unique lists

you can use:

dict1 = {'a': [[] for _ in range(5)], 'b': [[] for _ in range(5)]}

or you can use copy.deepcopy

import copy

dict1 = {'a': copy.deepcopy(empty_list_of_lists), 'b': copy.deepcopy(empty_list_of_lists)}

you can read more about shallow and deep copy operations here

in your code you are using a shallow copy but what you need a deep copy, from the above docs:

A shallow copy constructs a new compound object and then (to the
extent possible) inserts references into it to the objects found in
the original.

A deep copy constructs a new compound object and then, recursively,
inserts copies into it of the objects found in the original.

How to initialize a dict with keys from a list and empty value in Python?

dict.fromkeys directly solves the problem:

>>> dict.fromkeys([1, 2, 3, 4])
{1: None, 2: None, 3: None, 4: None}

This is actually a classmethod, so it works for dict-subclasses (like collections.defaultdict) as well.

The optional second argument, which defaults to None, specifies the value to use for the keys. Note that the same object will be used for each key, which can cause problems with mutable values:

>>> x = dict.fromkeys([1, 2, 3, 4], [])
>>> x[1].append('test')
>>> x
{1: ['test'], 2: ['test'], 3: ['test'], 4: ['test']}

How do I initialize a dictionary with a list of keys and values as empty sets in python3.6?

Using dictionary comprehension

d = {x: set() for x in [1, 2, 3]}

Or using collections.defaultdict

Create a list of empty dictionaries

List comprehensions to the rescue!

foo = [{} for _ in range(n)]

There is no shorter notation, I am afraid. In Python 2 you use xrange(n) instead of range(n) to avoid materializing a useless list.

The alternative, [{}] * n creates a list of length n with only one dictionary, referenced n times. This leads to nasty surprises when adding keys to the dictionary.

Using dict.fromkey() to initialize dictionary of lists results in strange .append() behavior

All your dictionary entries will reference the same list instance. So there is actually only one list.

In order to get distinct lists, you cannot use the fomkeys() method but a dictionary comprehension would work (because every iteration will create a distinct instance of the list):

output = {k:[] for k in ('a','b','c')}

How can I make multiple empty lists in Python?

A list comprehension is easiest here:

>>> n = 5
>>> lists = [[] for _ in range(n)]
>>> lists
[[], [], [], [], []]

Be wary not to fall into the trap that is:

>>> lists = [[]] * 5
>>> lists
[[], [], [], [], []]
>>> lists[0].append(1)
>>> lists
[[1], [1], [1], [1], [1]]

Python: How to initialize a nested list with empty values which i can append to

Try using a list comprehension within a list comprehension:

>>> [ [ [] for i in range(wid) ] for i in range(hgt) ]
[[[], [], []], [[], [], []], [[], [], []]]

Note this is preferred to list multiplication because each of these lists is unique. Compare:

>>> x = [ [[] for i in range(wid)] for i in range(hgt) ]
>>> x[1][1].append('a')
>>> x
[[[], [], []], [[], ['a'], []], [[], [], []]]

vs.

>>> y = [ [[]] * wid for i in range(hgt) ]
>>> y[1][1].append('a')
>>> y
[[[], [], []], [['a'], ['a'], ['a']], [[], [], []]]

vs.

>>> z = [ [[]] * wid ] * hgt
>>> z[1][1].append('a')
>>> z
[[['a'], ['a'], ['a']], [['a'], ['a'], ['a']], [['a'], ['a'], ['a']]]

Where, in the second and third cases, 'a' appears in multiple cells! And using None does not avoid this problem:

>>> m = [ [None] * wid ] * hgt
>>> m
[[None, None, None], [None, None, None], [None, None, None]]
>>> if m[1][1] is None:
... m[1][1] = ['a']
... else:
... m[1][1].append('a')
...
>>> m
[[None, ['a'], None], [None, ['a'], None], [None, ['a'], None]]

tl;dr - use the double list comprehension. In my opinion, it's the most readable option anyway.

How do I create a dictionary with keys from a list and values defaulting to (say) zero?

dict((el,0) for el in a) will work well.

Python 2.7 and above also support dict comprehensions. That syntax is {el:0 for el in a}.



Related Topics



Leave a reply



Submit