Asked  7 Months ago    Answers:  5   Viewed   25 times

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?

 Answers

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
 
radmen
answered 7 Months ago
75

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

In [18]: from importlib import reload

In [19]: 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
 
bimal
answered 4 Months ago
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
 
waylaidwanderer
answered 4 Months ago
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
 
Scheff's Cat
answered 4 Months ago
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
 
Ramacciotti
answered 3 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share