2D Array Unintended Assignment Bug - python

I want to create a 2D array, like so:
grid[y][x]
So that there are y amount of rows and x amount of columns.
Below is the way I did it, but I when I tried to assign the (0,0) of the array to contain the value '2', the code assigned the first value of each subarray to '2'.
Why is this happening? How should I pythonically instantiate a 2D array?
n = 4
x=0
y=0
grid = [[None]*n]*n
print grid
grid[y][x]='Here'
print grid

when you use * you create multiple references, it does not copy the data
so when you modify the first line to
[here,none,none,none]
you actually change all lines.
solution
[[None for i in range(n)] for j in range(n)]
Edit (from other post) Since only the lists are mutable (can change in place) you can also do
[[None]*n for j in range(n)].
Each of the rows are then still unique. If the None object could be changed in place this would not work.

grid = [[None]*n for i in range(n)]

Related

Taking n elements at a time from 1d list and add them to 2d list

I have a list making up data, and I'd like to take 4 elements at a time from this list and put them in a 2d list where each 4-element increment is a new row of said list.
My first attempts involve input to 1d list:
list.append(input("Enter data type 1:")) list.append(input("Enter data type 2:")) etc.
and then I've tried to loop the list and to "switch" rows once the index reaches 4.
for x in range(n * 4):
for idx, y in enumerate(list):
if idx % 4 == 0:
x = x + 1
list[y] = result[x][y]
where I've initialised result according to the following:
and
ran = int(len(list)/4)
result=[[0 for x in range(ran)] for j in range(n)]
I've also attempted to ascribe a temporary empty list that will append to an initialised 2D list.
`
row.append(list)
result=[[x for x in row] for j in range(n + 1)]
#result[n]=row
print(result)
n = n + 1
row.clear()
list.clear()
so that each new loop starts with an empty row, takes input from user and copies it.
I'm at a loss for how to make result save the first entry and not be redefined at second,third,fourth entries.
I think this post is probably what you need. With np.reshape() you can just have your list filled with all the values you need and do the reshaping after in a single step.

Original list changes despite using independent copies

I would like to iterate through all elements of a matrix (in my code a list of lists) and create an independent copy of that matrix everytime, when the checked element meets a certain condition.
Every time a copy is created, I would like to change one of the elements in the copied matrix (so that the original matrix stays the same). Every copy of the matrix should get an individual name.
After that, I would like to store that copied matrix in a list.
So, for example: Consider the original Matrix is a 2x2 Matrix, containing four integers (let's say the numbers 1 to 4, as shown in the code below). Now let's loop through the matrix elements and create a copy of the matrix everytime, when the checked element is larger than 3. So we should get one copy (because only one element, the number 4, is larger than 3). In this copied matrix, I change one of the elements (e.g. let's say adding the number 10 to the element that was checked). Then I store this copied matrix in a list. My code looks like this:
matrix = [[1,2],[3,4]]
new_copies = []
counter = 0
for i in range(0,2):
for k in range(0,2):
if matrix[i][k] > 3:
exec("item%s = matrix[:]" % counter)
exec("item%s[i][k] = matrix[i][k] + 10" % counter)
exec("new_copies.append(item%s)" % counter)
counter += 1
print(matrix)
print(new_copies)
If you run this code, you will see that the copied matrix is changed correctly and also is stored in the list.
But the original matrix also is changed. Why? I only manipulate the copied versions of the matrix, which should be independent from the original, since I follow this principle:
new_matrix = original_matrix[:]
Why it is happening
Lists are mutable objects, that is why even if you are creating a new list object by doing matrix[:], your sublists are still pointing to the same objects...
A first solution
Here is a first workaround:
matrix = [[1, 2], [3, 4]]
new_copies = []
counter = 0
for i in range(0, 2):
sublist = matrix[i][:]
for k in range(0, 2):
if matrix[i][k] > 3:
sublist[k] += 10
counter += 1
new_copies.append(sublist)
print(matrix)
print(new_copies)
Or with lists comprehension
If possible, you could also use list comprehension, in this case that would be:
new_copies = [[(e + 10 if e > 3 else e) for e in l] for l in matrix]
which will give you the same result that my previous proposition
Or with mutable objects
A nice solution would be to use tuple instead of lists, because they are immutable objects. But it won't be possible if you have to modify your matrix along your program.
Or with deepcopy
You could also use the deepcopy method from the copy library...
And you saw me coming...
I have to remind that the use of eval should be avoided if possible...

Python - Splitting lists of integers during iteration

I have an array of data where I'm taking a slice through a 3D array of floats and appending the numbers of the elements that satisfy a set of upper and lower bounds (also floats).
The first part of my code contains a nested for loop in the style of the following:
x_lst = []
for i in range(len(x1)):
for x in range(len(floatarray[0,:,0])):
if x1[i] <= floatarray[0,x,0] <= x2[i]:
x_lst.append(x)
#issues after this point
The inner loop compares the data in the array (floatarray[0,x,0]) with the boundaries x1 and x2, returning a list of integers, whilst the outer loop iterates through the values of the boundaries.
The issue I have is that the output (x_lst) is a single list, whereas I've been trying to produce a list of lists, with each sublist corresponding to the iterable i.
e.g.
#Desired output
x_lst = [[5,6,7,13,14],[21,22,23,36,37],[44,45,...
#Actual output
x_lst = [5,6,7,13,14,21,22,23,36,37,44,45,...
I feel like there's a very simple way of doing this, but I've not been able come up with anything that works (such as trying to use x_lst.split() after the append).
Also, any feedback on the question would be great as I'm still fairly new to SO.
It seems the following should work: why not create an intermediate sublist for each i, and add appropriate values to the sublist, then finally add the sublist to the main list?
x_lst = []
for i in range(len(x1)):
inner_list = [] # The sublist to be appended.
for x in range(len(floatarray[0,:,0])):
if x1[i] <= floatarray[0,x,0] <= x2[i]:
inner_list.append(x) # Add the numbers to the sublist.
# Issues after this point...
x_lst.append(inner_list) # Add the sublist to the main list.
Everything appears to be correct in the code except that you append into a 1-d array. For solving your problem you can simply change your code so that a temporary array named temp will append data in inner loop which would then be appended to your outer array x_lst as shown below:
x_lst = []
for i in range(len(x1))
temp=[]
for x in range(len(floatarray[0,:,0])):
if x1[i] <= floatarray[0,x,0] <= x2[i]:
temp.append(x)
x_lst.append(temp);
Okay, so Sam's answer is correct insofar as appending the values through the iteration, but trying it out with my code produced lists of lists of len(i) where each sublist contained all values of x that satisfied all elements of x1 and x2, instead of each list containing values specific to the [i]th element of x1 and x2, thus all the sublists were identical.
I got around this by replacing the inner for loop with a list comprehension, as follows, that gave the right result (in the desired form x_lst = [[5,6,7,13,14],[21,22,23,36,37],[44,45,...):
x_lst = []
for i in range(len(x1)):
y = [x for x in range(len(floatarray[0,:,0])) if x1[i] <= floatarray[0,x,0] <= x2[i]]
x_lst.append(y)

2 dimensions list (array?) in python

I have to create 2 functions that involve a 2 dimension list in order to make a grid for a basic Python game :
The first function must take in parameter an int n and return a list of 2 dimensions with n columns and n lines with all values to 0.
The second one must take a 2 dimension list in parameter and print the grid but return nothing.
Here is what I came with:
def twoDList(x, y):
arr = [[x for x in range(6)] for y in range(6)] # x = height and y = width
return arr
def displayGrid(arr):
for i in range(0, 5):
print(arr[i][i])
Could you please help me to improve the code regarding the instructions and help me to understand how to display the whole grid with the code please?
Here are 2 methods using no 3rd party libraries.
One simple way to create a 2D array is to keep appending an array to an array:
for x in range(10): #width
for y in range(10): #height
a.append(y) #you can also append other data is you want it to be empty, this just makes it 0-9
arr.append(a) #add the 1-9
a = [] #clear the inner array
Here, I re-created the same array (a) 10 times, so it's kind of inefficient, but the point is that you can use the same structure with custom data input to make your own 2D array.
Another way to get the exact same 2D array is list comprehension
arr = [[x for x in range(10)] for y in range(10)]
This is probably what you were trying to do with the code you provided, which is, as mentioned in the comments, syntactically incorrect.
To print, just tweak the code you have to have 2 loops: one for x and one for y:
for x in range(5):
for y in range(5):
print(arr[x][y])
I still see erros in your code:
In your first function, since x,y are your inputs, you want to USE them in your list comprehension. You're not using them in your code
def twoDList(x, y):
arr = [[x for x in range(6)] for y in range(6)] # x = height and y = width
return arr
In your example, no matter what the value of x or y is, you're getting a 6x6 grid. You want to use x and y and replace the fixed values you have over there (HINT: change your '6').
Won't do that for you,
In your print function, you might want to use two variables, once per each dimension, to use as indexes.
Also, don't use fixed values in here, get them from your input (i'm guessing this is homework, so won't put the whole code)
def displayGrid(arr):
for i in range(0, 5):
for j in range(0, 5):
print(arr[i][j])

How is this 2D array being sized by FOR loops?

Question background:
This is the first piece of Python code I've looked at and as such I'm assuming that my thread title is correct in explaining what this code is actually trying to achieve i.e setting a 2D array.
The code:
The code I'm looking at sets the size of a 2D array based on two for loops:
n = len(sentences)
values = [[0 for x in xrange(n)] for x in xrange(n)]
for i in range(0, n):
for j in range(0, n):
values[i][j] = self.sentences_intersection(sentences[i], sentences[j])
I could understand it if each side of the array was set with using the length property of the sentences variable, unless this is in effect what xrange is doing by using the loop size based on the length?
Any helping with explaing how the array is being set would be great.
This code is actually a bit redundant.
Firstly you need to realize that values is not an array, it is a list. A list is a dynamically sized one-dimensional structure.
The second line of the code uses a nested list comprehension to create one list of size n, each element of which is itself a list consisting of n zeros.
The second loop goes through this list of lists, and sets each element according to whatever sentences_intersection does.
The reason this is redundant is because lists don't need to be pre-allocated. Rather than doing two separate iterations, really the author should just be building up the lists with the correct values, then appending them.
This would be better:
n = len(sentences)
values = []
for i in range(0, n):
inner = []
for j in range(0, n):
inner.append(self.sentences_intersection(sentences[i], sentences[j]))
values.append(inner)
but you could actually do the whole thing in the list comprehension if you wanted:
values = [[self.sentences_intersection(sentences[i], sentences[j]) for i in xrange(n)] for j in xrange(n)]

Categories