0

How do I create a dictionary of lists? Here is what I tried:

zigzag = dict.fromkeys(range(1, 4),[])
for i in range(1, 4):
    zigzag[i].extend(range(i, 13 , 4))

What I expected to get was:

{
  1: [1,5,9,13],
  2: [2,6,10],
  3: [3,7,11]
}

But the actual result had the same list in each value:

{
  1: [1, 5, 9, 2, 6, 10, 3, 7, 11],
  2: [1, 5, 9, 2, 6, 10, 3, 7, 11],
  3: [1, 5, 9, 2, 6, 10, 3, 7, 11]
}

I don't know how that result happened. How can I get my expected answer?

Aposhian
  • 801
  • 1
  • 10
  • 27
Sanji
  • 83
  • 1
  • 7

1 Answers1

1

From the documentation on dict.fromkeys():

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.

In Python, assignments of mutable objects like a list do not create a new object: they just make a new reference to the existing object. So what you are seeing is that each value in the dictionary is actually referencing the same empty list that you passed into dict.fromkeys().

Instead you could simply do

zigzag = {}
for i in range(1, 4):
    zigzag[i] = list(range(i, 14 , 4))

Or using dictionary comprehension like the documentation recommmends:

zigzag = { i: list(range(i, 14, 4)) for i in range(1,4) }

Further reading on mutable vs immutable data types in Python:

Note on range()

Also, if you are expecting 13 to be present in zigzag[1], then you should use a stop value of 14, not 13. The stop value is exclusive. From the docs on range():

For a positive step, the contents of a range r are determined by the formula r[i] = start + step*i where i >= 0 and r[i] < stop.

Aposhian
  • 801
  • 1
  • 10
  • 27