How to expand a 2d array based on a number - python

I want that:
num = 3
array = [0,0,0,0,0]
become this:
array = ([0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0])
I've tried this:
array = ([0,0,0,0,0],)*num
and this:
array = [[0,0,0,0,0]]*num
but when I set the values, it sets it everywhere.
num = 3
array = [[0,0,0,0,0]]*num
print(array)
array[0][0] = 1
array[1][1] = 2
print(array)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 2, 0, 0, 0], [1, 2, 0, 0, 0], [1, 2, 0, 0, 0]]
when it should be that:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 0, 0, 0, 0]]

Use List Comprehensions to build the 2D list . The thing that you are doing is actually making 3(num) references to the same list !! To understand it much better, consider this example
>>> a=b=[5]
>>> a[0] = 6
>>> a
[6]
>>> b
[6]
So use list comprehensions, so that all the inner lists are "unique".
num = 3
array = [[0,0,0,0,0] for i in range(num)]
print(array)
array[0][0] = 1
array[1][1] = 2
print(array)
Output:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
[[1, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 0, 0, 0, 0]]

Related

Change zeroes in 2D array one by one, and put the resulting arrays into another array in Python [duplicate]

This question already has answers here:
How do I compute all possibilities for an array of numbers/bits (in python, or any language for that matter)
(5 answers)
Closed 2 years ago.
I am trying to achieve the following. I have a 2D array, which is of a 4x4 dimension. I want to get all possibilities, where I can insert a single 1 instead of a zero, and return an array, which contains all of these possibilities
So if we take:
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
would result in:
[[1, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
...
There would be a total of 14 entries in the resulting array, since there were 14 zeroes in the input array.
The problem is, that the code I have currently should work, as far as I understand, but I can't seem to get where it goes wrong.
def getPossibilities(arr):
p = []
for i in range(4):
for j in range(4):
if arr[i][j] == 0:
p.append(arr)
p[-1][i][j]=1
return p
for i in getPossibilities([[0,1,0,0],[0,0,1,0],[0,0,0,0],[0,0,0,0]]):
print(i)
This results in 14 arrays of solid ones.
I included the way I check the results, in case there is an error there. I also tried with first copying the arr array into a temporary one, then make the changes, but to no avail.
What goes wrong here? I cannot seem to find an answer. Also, is there a more elegant and faster way of doing this? It would be really beneficial for my usecase.
Thank you very much in advance!
This is somewhat tricky but since you have a list of lists, the copy won't work and you will be changing the array every time, what you need is deepcopy:
import copy
def getPossibilities(arr):
p = []
for i in range(4):
for j in range(4):
if arr[i][j] == 0:
tmp = copy.deepcopy(arr)
tmp[i][j]=1
p.append(tmp)
return p
for i in getPossibilities([[0,1,0,0],[0,0,1,0],[0,0,0,0],[0,0,0,0]]):
print(i)
[[1, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [1, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [1, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 1, 0, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 1, 0]]
[[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 1]]

Zero-out array elements with matching indices

I'd like to "zero-out" all elements of an n-dimensional array that are in positions with two or more matching indices. In two dimensions, this is effectively np.fill_diagonal() but that function becomes inadequate when a third dimension is considered.
Below is the brute-force version of what I'd like to do. Is there any way to clean this up and make it work in n dimensions?
x = np.ones([3,3,3])
x[:,0,0] = 0
x[0,:,0] = 0
x[0,0,:] = 0
x[:,1,1] = 0
x[1,:,1] = 0
x[1,1,:] = 0
x[:,2,2] = 0
x[2,:,2] = 0
x[2,2,:] = 0
print(x)
One way is np.einsum:
>>> a = np.ones((4,4,4), int)
>>> for n in range(3):
... np.einsum(f"{'iijii'[n:n+3]}->ij", a)[...] = 0
...
>>> a
array([[[0, 0, 0, 0],
[0, 0, 1, 1],
[0, 1, 0, 1],
[0, 1, 1, 0]],
[[0, 0, 1, 1],
[0, 0, 0, 0],
[1, 0, 0, 1],
[1, 0, 1, 0]],
[[0, 1, 0, 1],
[1, 0, 0, 1],
[0, 0, 0, 0],
[1, 1, 0, 0]],
[[0, 1, 1, 0],
[1, 0, 1, 0],
[1, 1, 0, 0],
[0, 0, 0, 0]]])
General (ND) case:
>>> from string import ascii_lowercase
>>> from itertools import combinations
>>>
>>> a = np.ones((4,4,4,4), int)
>>> n = a.ndim
>>> ltrs = ascii_lowercase[:n-2]
>>> for I in combinations(range(n), 2):
... li = iter(ltrs)
... np.einsum(''.join('z' if k in I else next(li) for k in range(n)) + '->z' + ltrs, a)[...] = 0
...
>>> a
array([[[[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, 1],
[0, 0, 1, 0]],
[[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 0, 0],
[0, 1, 0, 0]],
<snip>

Python List Assignment Issues

#DeckOfCards
deck = []
filler= [0, 0, 0, 0]
def deck_generator():
counter = 0
for i in range (52):
counter += 1
deck.append(filler)
return deck
def deck_values(i):
k = 4
temp = (i + 1) % k
return temp
deck = deck_generator()
for i in range(52):
deck[i][0] = deck_values(i)
The goal with this code is to assign the values 0-3 inclusive to the first index of the inner list to all values in the outer list.
[[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0], [0, 0, 0, 0]] and so on. For some reason the assignment just does not work. Thanks in advance.
Append a copy of the list instead of the list itself.
deck.append(filler[:])
Try this
deck = []
for i in range(52):
deck.append([i % 4, 0, 0, 0])
print (deck)
Running this code prints (edited for ease of viewing):
[[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],
[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0]]
are you sure you want to get [[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0], [0, 0, 0, 0]] ?
first of all, you should use the copy of filter and then you can get a list like:
[[1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0], [0, 0, 0, 0],...]
but if you want to get the result [[0, 0, 0, 0], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0],...]
your codes should be like this:
deck = []
filler= [0, 0, 0, 0]
def deck_generator():
counter = 0
for i in range (52):
counter += 1
deck.append(filler[:])
return deck
def deck_values(i):
k = 4
temp = i % k #not temp = (i+1) % k
return temp
deck = deck_generator()
for i in range(52):
deck[i][0] = deck_values(i)
print(deck)
I think the issue with it is temp=(i+1)%k as we do not need to add 1 to 1. It should start from 0. In addition to this, you need to append properly so it works. The code would look like this:
#DeckOfCards
deck = []
filler= [0, 0, 0, 0]
def deck_generator():
counter = 0
for i in range (52):
counter += 1
deck.append(filler[:])
return deck
def deck_values(i):
k = 4
temp = (i) % k
return temp
deck = deck_generator()
for i in range(52):
deck[i][0] = deck_values(i)

How to for loop in reverse?

I'm making a water simulation program, and I need it to do a for loop through y, x. But I need it to check the most bottom y first, then up. This is my lvl:
lvl = [[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
I need it to check lvl[4] and then lvl[3], lvl[2], etc. Please help!
NB: I'm using nested for loops, so I can check y, x.
You can use the reversed built-in method to reverse the ordering of your list of lists:
for li in reversed(lvl):
print li
Output:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
If you're using for loops, you can use range to generate a reversed sequence to index lvl with.
>>> range(4,-1,-1)
[4, 3, 2, 1, 0]
i.e., maybe something similar to:
>>> for i in range(4,-1,-1):
... print lvl[i]
...
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
>>>

Initializing matrix in Python using "[[0]*x]*y" creates linked rows?

Initializing a matrix as so seems to link the rows so that when one row changes, they all change:
>>> grid = [[0]*5]*5
>>> grid
[[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]]
>>> grid[2][2] = 1
>>> grid
[[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]]
How can I avoid this?
grid = [[0]*5 for i in range(5)]
Note: [int]*5 copies the int 5 times (but when you copy an int you just copy the value). [list]*5 copies the reference to the same list 5 times. (when you copy a list you copy the reference that points to the list in memory).

Categories

Resources