简体   繁体   中英

Having trouble replacing elements in a 2d list with a 1d list using for-loops

I am asked to replace some elements in a 2d list with elements from a 1D list. The rule is to replace the first row of list1 with list2. The elements in the next row will be replaced by 3 times each element from the previous row. So the second row will contain 33, 39, 45,and 51, and the third row 99, 117, 135, and 153... all the way to the 10th row.

Here is my code:

list1 = [[0]*4]*10
list2 = [11,13,15,17]

list1[0] = list2

i = 1        
for i in range(9):
    j = 0
    for j in range(4):
        list1[i][j] = list2[j]*(3**i)
        j+=1
    i+=1

The result I got from this code basically only contains the correct first row, but the rest of the rows after that are all 72171, 85293, 98415, and 111537 (which is 3 to the 8th). I am not sure which part is giving me the error.

Here are some comments on your code and examples of how to make it do what the question describes:

(1.) References vs copies: list1 = [[0]*4]*10 creates a single 4-element list and populates list1 with 10 references to it (NOT 10 copies of it).

For an example of what this implies, watch this:

list1 = [[0]*4]*10
list1[1][0] = 33
list1[1][1] = 39
list1[1][2] = 45
list1[1][3] = 51
print(list1)

... gives this:

[[33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51], [33, 39, 45, 51]]

In other words, updating one list element within list1 updates them all, since each element of list1 is just a reference to the same list.

If this is not what you want, you can use list1 = [[0]*4 for _ in range(10)] instead to give you a distinct list (10 in total) for each index in list1 :

list1 = [[0]*4 for _ in range(10)]
list1[1][0] = 33
list1[1][1] = 39
list1[1][2] = 45
list1[1][3] = 51
print(list1)

... gives:

[[0, 0, 0, 0], [33, 39, 45, 51], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Your code as written would tend to imply that the second approach above is what is needed.

(2.) Code fix assuming nested lists cannot be replaced: It's unclear from the question whether whether you are allowed to replace each list in list1 to get the desired values, or if you are expected to leave the nested lists in place and simply modify their numerical contents.

If list replacement is not allowed, then your code can be rewritten like this:

list1 = [[0]*4 for _ in range(10)]
list2 = [11,13,15,17]
list1[0][:] = list2

for i in range(9):
    for j in range(4):
        list1[i + 1][j] = list2[j]*(3**(i + 1))
print(list1)

... giving:

[[11, 13, 15, 17], [33, 39, 45, 51], [99, 117, 135, 153], [297, 351, 405, 459], [891, 1053, 1215, 1377], [2673, 3159, 3645, 4131], [8019, 9477, 10935, 12393], [24057, 28431, 32805, 37179], [72171, 85293, 98415, 111537], [216513, 255879, 295245, 334611]]

Note that these changes were made to your code:

  • Changed the initialization of list1 to allocate 10 distinct nested lists.
  • Eliminated i = 1 (not needed because the for loop takes care of initializing i ), j = 0 (similar reason), j+=1 (not needed because the for loop takes care of updating j ) and i+=1 (similar reason).
  • Changed list1[i][j] to list1[i + 1][j] to fix the indexing.
  • Changed 3**i to 3**(i + 1) to calculate the correct multiplier.

(3.) Code fix assuming nested lists can be replaced: In this case, your looping logic can be simplified and you don't need to use nested lists when initializing list1 .

Here is a long-hand way to do what you ask which will overwrite the contents of list1 with new nested lists that have the desired values:

list1 = [None] * 10
list2 = [11,13,15,17]
list1[0] = list2
mul = 3
for i in range(1, len(list1)):
    temp = [0] * len(list2)
    for j in range(len(list2)):
        temp[j] = mul * list2[j]
    list1[i] = temp
    mul *= 3
print(list1)

Here is a way that uses a list comprehension inside a loop:

list1 = [None] * 10
list2 = [11,13,15,17]
list1[0] = list2
mul = 3
for i in range(1, len(list1)):
    list1[i] = [mul * v for v in list2]
    mul *= 3
print(list1)

And finally, here is a very compact nested list comprehension approach:

list1 = [None] * 10
list2 = [11,13,15,17]
list1 = [[(3 ** i) * v for v in list2] for i in range(len(list1))]

the reason that happened is that you are working on a copy of 0 elements of list1, so whenever you modify further everything will be replaced with the new value, it's not a copy its the same object in reference.

 for i in range(9):
     tmp = []
     for j in range(4):
         tmp.append(list2[j]*(3**i))
     list1[i] = tmp

this is all you need

You can make this much easier using numpy arrays:

import numpy as np 
list1 = np.zeros((10,4), dtype=int)
list1[0] = [11,13,15,17]

for i in range(1,10):
    list1[i] = 3*list1[i-1]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM