Two ways to create 2D array in python - python

What is the difference between the below two ways for creating 2d array in python?
def arrays(row, column):
myList = [[None]*column for i in range(row)]
def arrays(row, column):
myList = [[None]*column]*row

In the first case, separate pointers are used to store your sublists.
In the second instance, the same pointer is used. So changing the value of one will also change the others.
Here's an illustrative example:-
def arrays1(row, column):
return [[None]*column for i in range(row)]
def arrays2(row, column):
return [[None]*column]*row
x = arrays1(2, 2)
y = arrays2(2, 2)
x[0][0] = 1
y[0][0] = 1
print(x) # [[1, None], [None, None]]
print(y) # [[1, None], [1, None]]

Related

How can I add two items to a list copmprehension at once

I have a simple for loop like this:
for i in range(3):
if i == 1:
for x in [0, 2]:
free_spots.append([x, i])
else:
free_spots.append([1, i])
which outputs this list
[[1, 0], [0, 1], [2, 1], [1, 2]]
I planned to convert this to a list compehension like so but ran into a problem:
[[x, i] for x in [0, 2] if i == 1 else [1, i] for i in range(3)]
This causes an error, which I've tried fixing it like this:
[[[x, i] for x in [0, 2]] if i == 1 else [1, i] for i in range(3)]
and while that this now runs it also creates this:
[[1, 0], [[0, 1], [2, 1]], [1, 2]]
and I don't want items 2 and 3 to be in a list together. Is it possible to do something like this?:
[[0,i],[2,i] if i == 1 else [1, i] for i in range(3)]
If you really want to do it in one line, how about this?
free_spots = [val for sublist in [([[x, i] for x in [0,2]] if i == 1 else [[1, i]]) for i in range(3)] for val in sublist]
# This effectively creates a list of lists containing the values you want
main_list = [([[x, i] for x in [0,2]] if i == 1 else [[1, i]]) for i in range(3)]
# And then flattens it
free_spots = [val for sublist in main_list for val in sublist]
But the others are right. This is not a good idea unless you have a good reason. I can barely understand my own code now that I've written it which is not python zen.
You could do it in two steps.
free_spots = [[1, i] for i in range(3)]
free_spots[1:2] = [[x, 1] for x in [0, 2]]
The slice assignment is equivalent to the nested loop in the for loops.
However, this doesn't generalize well if you have multiple exceptions in the loop.
As already pointed out in the comments, it is not elegant to create such a list comprehension statement. Therefore, as suggested in Karl's comment, a generator is a preferred solution.
To use a generator, your code will look somehow like this:
# Create a generator function
def generate_data():
for i in range(3):
if i == 1:
for x in [0, 2]:
yield [x, i]
else:
yield [1, i]
# Use it
print(list(generate_data()))

Bug when edit values of nested list that generated using multiplication [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 2 years ago.
Welcome All 😊
I try to make list using python named mylist with 3 element each element contain other list contain 2 element like these 👇
[[None,None]]*3
When try to edit first nested list items in my list by set mylist[0][0] = 1 and mylist[0][1] = 2
Then try to print mylist This is output : [[1, 2], [1, 2], [1, 2]] It edit all list items.
However when create it manually like mylist = [[None, None], [None, None], [None, None]] then try to make my edit edition done correctly.
First Case Code :
mylist = [[None,None]]*3
mylist[0][0] = 1
mylist[0][1] = 2
print(mylist)
First Case Output:
[[1, 2], [1, 2], [1, 2]]
Second Case Code :
mylist = [[None, None], [None, None], [None, None]]
mylist[0][0] = 1
mylist[0][1] = 2
print(mylist)
Second Case Output:
[[1, 2], [None, None], [None, None]]
That is because multiplying a list doesn't actually create copies of itself like how a string does. For the effect you are looking for, you can use a module called NumPy, use numpy_r for that.
import numpy as np
mylist = np.array([[None, None]] * 3])
print(mylist)
Output will be:
[[[None None]
[None None]
[None None]]]
Or:
import numpy as np
mylist = np.r_[[[None, None]] * 3]
print(mylist)
Which outputs:
[[None None]
[None None]
[None None]]
The second one doesn't have an extra dimension, if you didn't figure that out.
If you don't know much about NumPy then click here, you can check here to install NumPy.
And if you want to access for eg. the first item, the you use mylist[0][0] but in NumPy arrays, you use mylist[0, 0].
And #Guimoute has the answer in the comments for doing it using standard python without modules.
Edit: I had written some code wrong, I have corrected it. Don't get more frustrated for the code not working, there was just an error.

Multi-dimensional array is entirely (aside the first value) set to appended value

I'm making a function to find all the combinations for a given set of options. When I append a combination as a list to the main list of total combinations (the combinations are indexes, to be taken from the list of options later), all of the existing lists are changed to the list I just appended, apart from the first.
def allCombos(opts):
limit = len(opts) - 1
combos = []
for n in range(1, 3):
combo = [0] * n
print(combo) # going to remove this
goal = [limit] * n
pointer = 0
overflowed = False
while True:
if combo[pointer] == limit:
pointer += 1
overflowed = True
else:
if overflowed:
combo[pointer] += 1
for i in range(pointer):
combo[i] = 0
pointer = 0
combos.append(combo)
print(combo) # I will change this
else:
combo[pointer] += 1
combos.append(combo)
print(combo) # and this
if combo == goal:
break
allCombos(["foo", "bar"])
outputs
[0]
[1]
[0, 0]
[1, 0]
[0, 1]
[1, 1]
whereas
def allCombos(opts):
limit = len(opts) - 1
combos = []
for n in range(1, 3):
combo = [0] * n
goal = [limit] * n
pointer = 0
overflowed = False
while True:
if combo[pointer] == limit:
pointer += 1
overflowed = True
else:
if overflowed:
combo[pointer] += 1
for i in range(pointer):
combo[i] = 0
pointer = 0
combos.append(combo)
print(combos) # changed
else:
combo[pointer] += 1
combos.append(combo)
print(combos) # changed
if combo == goal:
break
print("\n" + str(combos)) #added
allCombos(["foo", "bar"])
outputs
[[1]]
[[1], [1, 0]]
[[1], [0, 1], [0, 1]]
[[1], [1, 1], [1, 1], [1, 1]]
[[1], [1, 1], [1, 1], [1, 1]]
This seems odd, as the only specified modifications of combos seems to be the appending.
I've looked for other questions with similar issues, but I couldn't find any.
Thanks in advance!
You're appending several references to combo to combos. When you change combo, those references all point to the modified list. Compare to this simple example:
>>> x=[1,2]
>>> y=[]
>>> y.append(x)
>>> y.append(x)
>>> y
[[1, 2], [1, 2]]
>>> x[0]+=1
>>> y
[[2, 2], [2, 2]]
>>>
Notice that combo originally starts out as [0], but you never see that in the output. That's because it's been changed to [1]. When you get to the top of the loop, you set combo to [0,0]. Why doesn't that affect combos? Because you've set combo to a new value. The reference in combos points to a different object than the newly-created combo. Now you start changing combo in place, and appending it to the list. You just get multiple copies of the same thing.
If this isn't clear, try setting the limit to 3 instead of 2. Can you predict what the output will be?
I think that Gary van der Merwe made a good suggestion, but I believe he's thinking of itertools.product, not itertools.combinations.

Transposing a matrix using loops

Given the matrix
matrix = [[2, None],
[2, None]]
I need to compute the transpose of this. I did the following:
def transpose(matrix):
# Makes a copy of the matrix
result = matrix
# Computes tranpose
for i in range(2):
for j in range(2):
result[j][i] = matrix[i][j]
return result
But this gives me the false result:
[[2, None],
[None, None]]
while it should be
[[2, 2],
[None, None]]
Can someone tell me where I went wrong with my code?
You a referencing to the same matrix, try initializing a new one:
def transpose(matrix):
# Makes a copy of the matrix
result = [[None]* len(x) for x in matrix]
# Computes tranpose
for i in range(2):
for j in range(2):
result[i][j] = matrix[j][i]
return result
You can also do it for a generic matrix using list comprehesion
def transpose(matrix):
return [[matrix[i][j] for i in range(len(matrix[j]))] for j in range(len(matrix))]
The problem is that the variable result refers to matrix, that is, you do not make a copy, so in the for-loop you actually also change matrix. You can solve this by making a copy of matrix in result with list:
result = [list(x) for x in matrix]
See the question: How to clone or copy a list?
Note that an easier way is to use NumPy:
import numpy as np
matrix = np.matrix([[2, None],[2, None]])
then use matrix.T to get the transpose:
matrix([[2, 2],
[None, None]], dtype=object)
# We can use the below method also:
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
mat_trans = []
trans = []
trans1 = []
trans2 = []
trans3 = []
for row in matrix:
for i in range(4):
if i == 0:
trans.append(row[i])
if i == 1:
trans1.append(row[i])
if i == 2:
trans2.append(row[i])
if i == 3:
trans3.append(row[i])
mat_trans.append(trans)
mat_trans.append(trans1)
mat_trans.append(trans2)
mat_trans.append(trans3)
trans = []
print(mat_trans)
Assuming that the matrix is rectangular (i.e. same list size in all one-D arrays), one can simply write a transpose as the following.
def transpose(matrix):
num_rows = len(matrix)
num_cols = len(matrix[0])
result = []
for j in range(num_cols):
rowresult = []
for i in range(num_rows):
rowresult.append(matrix[i][j])
result.append(rowresult)
return result
Note: This is not the most efficient implementation.

Python - Erroneous result for two different matrixes in nested for loop

I have a problem with matrix operations in nested loop. I looked on stackoverflow before posting this question, all the subjects I found treated only one matrix.
My loop tries to computes two matrixes, giving 2 for each element in the first one and 1 in the second one. However the same matrix is given as an output.
I tried to duplicate the loops with one matrix in each, but the same erroneous result was given.
Thank you for your help!
dummy_matrix = [[0 for x in range(2)] for x in range(2)]
other_matrix = dummy_matrix
for x in range(2):
for i in range(2):
dummy_matrix[x][i] = 2
other_matrix[x][i] = 1
print 'dummy_matrix =',dummy_matrix
print 'other_matrix =',other_matrix
The answer is
dummy_matrix = [[1, 1], [1, 1]] # expected result : [[2, 2], [2, 2]]
other_matrix = [[1, 1], [1, 1]]
When you write
other_matrix = dummy_matrix
you're asking Python to bind the name other_matrix to the same object that dummy_matrix is bound to. So
dummy_matrix[x][i] = 2
other_matrix[x][i] = 1 # overwrites the previous value
Just do
other_matrix = [[0 for x in range(2)] for x in range(2)]
instead.
The problem is in this line
other_matrix = dummy_matrix
You are not creating a copy of dummy_matrix with this line, but you are making other_matrix also to point to the same list which dummy_matrix is also pointing to. To actually create a copy, you can use slicing notation like this
other_matrix = dummy_matrix[:]

Categories

Resources