# Nested List Indices [duplicate]

I have experienced some problem by using a nested list in Python in the code shown bleow.

Basically, I have a 2D list contains all 0 values, I want to update the list value in a loop.

However, Python does not produce the result I want. Is there something that I misunderstand about range() and Python list indices?

some_list = 4 * [(4 * [0])]
for i in range(3):
for j in range(3):
some_list[i+1][j+1] = 1
for i in range(4):
print(some_list[i])

The results I expected are:

[0, 0, 0, 0]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]

But the actual results from Python are:

[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]

What's going on here?

94

The problem is caused by the fact that python chooses to pass lists around by reference.

Normally variables are passed "by value", so they operate independently:

>>> a = 1
>>> b = a
>>> a = 2
>>> print b
1

But since lists might get pretty large, rather than shifting the whole list around memory, Python chooses to just use a reference ('pointer' in C terms). If you assign one to another variable, you assign just the reference to it. This means that you can have two variables pointing to the same list in memory:

>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]

So, in your first line of code you have 4 * [0]. Now [0] is a pointer to the value 0 in memory, and when you multiply it, you get four pointers to the same place in memory. BUT when you change one of the values then Python knows that the pointer needs to change to point to the new value:

>>> a = 4 * [0]
>>> a
[0, 0, 0, 0]
>>> [id(v) for v in a]
[33302480, 33302480, 33302480, 33302480]
>>> a[0] = 1
>>> a
[1, 0, 0, 0]

The problem comes when you multiply this list - you get four copies of the list pointer. Now when you change one of the values in one list, all four change together:

>>> a[0][0] = 1
>>> a
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]

The solution is to avoid the second multiplication. A loop does the job:

>>> some_list = [(4 * [0]) for _ in range(4)]
Tuesday, June 1, 2021

75

The reload built-in function has been moved to importlib module in Python 3.4:

In [18]: from importlib import reload

Reload the module and return it.

The module must have been successfully imported before.

As pointed out by @JPaget in comments reload() function has been moved from imp to importlib module in Python 3.4+. From what's new in Python 3.4:

The reload() function has been moved from imp to importlib as part of the imp module deprecation

Thursday, August 12, 2021

58

use the following to convert to a timestamp in python 2

int((mod_time.mktime(first_run.timetuple())+first_run.microsecond/1000000.0))

Sunday, August 22, 2021

96

The for ... in ... clauses inside a list comprehension need to go in the same order as if they were normal for-loops:

>>> test = [[1, 2, 3], [4, 5], [6, 7, 8]]
>>> t3 = [y for x in test for y in x]
>>> t3
[1, 2, 3, 4, 5, 6, 7, 8]
>>>
Friday, August 27, 2021

63

Firstly, list, set and string are already builtin functions, so using these names is not recommended. I also think your over complicating the problem slightly, since all you need to do is group the letters together, and do some summing of the values afterwards.

In order to make this problem easier for yourself, you need to somehow group the first values of each list, and take the sum of the values after that. One possible way is to group the first values with a collections.defaultdict, then sum the corresponding values afterwards:

from collections import defaultdict

lsts = [['a',14,2], ['b',10,1], ['a',3,12], ['r',5,5], ['r',6,13]]

groups = defaultdict(list)
for letter, first, second in lsts:
groups[letter].append([first, second])
# defaultdict(<class 'list'>, {'a': [[14, 2], [3, 12]], 'b': [[10, 1]], 'r': [[5, 5], [6, 13]]})

result = []
for key, value in groups.items():
sums = [sum(x) for x in zip(*value)]
result.append([key] + sums)

print(result)

Which Outputs:

[['a', 17, 14], ['b', 10, 1], ['r', 11, 18]]

The resultant list can also be written with this list comprehension:

result = [[[key] + [sum(x) for x in zip(*value)]] for key, value in groups.items()]

Another way is to use itertools.groupby:

from itertools import groupby
from operator import itemgetter

grouped = [list(g) for _, g in groupby(sorted(lsts), key = itemgetter(0))]
# [[['a', 3, 12], ['a', 14, 2]], [['b', 10, 1]], [['r', 5, 5], ['r', 6, 13]]]

result = []
for group in grouped:
numbers = [x[1:] for x in group]
sums = [sum(x) for x in zip(*numbers)]
result.append([[group[0][0]] + sums])
print(result)

Which also outputs:

[['a', 17, 14], ['b', 10, 1], ['r', 11, 18]]

Note: The second approach could also be written as a big list comprehension:

result = [[[group[0][0]] + [sum(x) for x in zip(*[x[1:] for x in group])]] for group in [list(g) for _, g in groupby(sorted(lsts), key = itemgetter(0))]]

But this is ugly and unreadable, and shouldn't be used.

Saturday, December 4, 2021