I am writing code to make a bot for the math game "Dandelions" and in order to do so, I take all columns, rows, and diagonals that contain the number 1. Then, with this list of lists that contain the number 1, I need to separate them using a for loop. However, when running this for loop I get an error saying that the pop index is out of range, but when I run the code with each individual i value, I don't get an error. It is the last for loop at the very end of the code that is causing this problem. Please help! Note: Even when running the for loop with a range of 3, it still outputs an error. Only indexes 0 and 2 are outputted.
row_1 = [0, 0, 0, 0, 0]
row_2 = [0, 1, 0, 0, 0]
row_3 = [0, 0, 0, 0, 0]
row_4 = [0, 0, 0, 0, 0]
row_5 = [0, 0, 0, 0, 0]
col_1 = [0, 0, 0, 0, 0]
col_2 = [0, 0, 1, 0, 0]
col_3 = [0, 0, 0, 0, 0]
col_4 = [0, 0, 0, 0, 0]
col_5 = [0, 0, 0, 0, 0]
#diagonals 1-9 go from left to right, while diagonals 10-18 go from right to left
dia_1 = [0]
dia_2 = [0, 0]
dia_3 = [0, 0, 0]
dia_4 = [0, 0, 0, 0]
dia_5 = [0, 0, 0, 1, 0]
dia_6 = [0, 0, 0, 0,]
dia_7 = [0, 0, 0]
dia_8 = [0, 0]
dia_9 = [0]
dia_10 = [0]
dia_11 = [0, 0]
dia_12 = [0, 0, 0]
dia_13 = [0, 0, 0, 0]
dia_14 = [0, 0, 0, 0, 1]
dia_15 = [0, 0, 0, 0,]
dia_16 = [0, 0, 0]
dia_17 = [0, 0]
dia_18 = [0]
dia = [dia_1, dia_2, dia_3, dia_4, dia_5, dia_6,
dia_7, dia_8, dia_9, dia_10, dia_11, dia_12,
dia_13, dia_14, dia_15, dia_16, dia_17, dia_18]
row = [row_1, row_2, row_3, row_4, row_5]
col = [col_1, col_2, col_3, col_4, col_5]
possible = []
for i in dia:
if 1 in i:
possible.append(i)
for i in row:
if 1 in i:
possible.append(i)
for i in col:
if 1 in i:
possible.append(i)
for i in range(0, 4):
print(possible.pop(i))
The for loops that are giving you the out-of-range error wrap them on a try-except block, in the exception add new logic to ignore or fix the out of range; for instance:
try:
for i in range(0, 4):
print(possible.pop(i))
except:
#correct your out-of-range:
pass
Seems you did not get my hint and the only answer so far is not very helpful.
To reproduce the problem, let's hard-code possible, since everything before the last loop does not really matter.
possible = [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
print(f"Possible before loop: {possible}")
for i in range(0, 4):
print(f"Item at pos {i}: {possible.pop(i)}")
print(f"Possible after pop: {possible}")
Output:
Possible before loop: [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
Item at pos 0: [0, 0, 0, 1, 0]
Possible after pop: [[0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
Item at pos 1: [0, 1, 0, 0, 0]
Possible after pop: [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0]]
Traceback (most recent call last):
File "test.py", line 5, in <module>
print(f"Item at pos {i}: {possible.pop(i)}")
IndexError: pop index out of range
Explanation:
As I said before, i keeps increasing, but at the same time, you are removing items from possible.
After the first iteration possible is [[0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]].
But during the next (the second) iteration, you are popping the item at index 1, which is [0, 1, 0, 0, 0] - you were probably expecting [0, 0, 0, 0, 1].
During the third iteration, possible only holds two items: [[0, 0, 0, 0, 1], [0, 0, 1, 0, 0]] but you are trying to pop the item at index 2, which is when the pop index out of range error happens.
Why not simple iterate your list and print the items instead of popping them?
possible = [[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0]]
for item in possible:
print(item)
Output:
[0, 0, 0, 1, 0]
[0, 0, 0, 0, 1]
[0, 1, 0, 0, 0]
[0, 0, 1, 0, 0]
I have an array a of ones and zeroes (it might be rather big)
a = np.array([[1, 0, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0],
[0, 1, 1, 0, 0, 1],
[0, 0, 0, 1, 1, 1])
in which the "upper" rows are more "important" in the sense that if there is 1 in any column of the i-th row, then all ones in that columns in the following rows must be zeroed.
So, the desired output should be:
array([[1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
In other words, there should only be single 1 per column.
I'm looking for a more numpy way to do this (i.e. minimising or, better, avoiding the loops).
Your array:
[[1, 0, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0],
[0, 1, 1, 0, 0, 1],
[0, 0, 0, 1, 1, 1]]
Transpose it with numpy:
a = np.transpose(your_array)
Now it looks like this:
[[1, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 0],
[1, 0, 0, 1],
[0, 1, 0, 1],
[0, 0, 1, 1]]
Zero all the non-zero (and "not upper") elements row wise:
res = np.zeros(a.shape, dtype="int64")
idx = np.arange(res.shape[0])
args = a.astype(bool).argmax(1)
res[idx, args] = a[idx, args]
The output of res is this:
#### Output
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0]]
Re-transpose your array:
a = np.transpose(res)
[[1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
EDIT: Thanks to #The.B for the tip
An alternative solution is to do a forward fill followed by the cumulative sum and then replace all values which are not 1 with 0:
a = np.array([[1, 0, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0],
[0, 1, 1, 0, 0, 1],
[0, 0, 0, 1, 1, 1]])
ff = np.maximum.accumulate(a, axis=0)
cs = np.cumsum(ff, axis=0)
cs[cs > 1] = 0
Output in cs:
array([[1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
EDIT
This will do the same thing and should be slightly more efficient:
ff = np.maximum.accumulate(a, axis=0)
ff ^ np.pad(ff, ((1,0), (0,0)))[:-1]
Output:
array([[1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
And if you want to do the operations in-place to avoid temporary memory allocation:
out = np.zeros((a.shape[0]+1, a.shape[1]), dtype=a.dtype)
np.maximum.accumulate(a, axis=0, out=out[1:])
out[:-1] ^ out[1:]
Output:
array([[1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
You can traverse through each column of array and check if it is the first one -
If Not: Make it 0
for col in a.T:
f=0
for x in col:
if(x==1 and f==0):
f=1
else:
x=0
I need help with shifting and deleting elements in a 2-dimensional array.
If the value in a list is negative and their is a list above it with positive values in the same location. It should shift everything down, causing the negative values to disappear.
If there isn't any list above it or the corresponding values in the list above are just 0. It will replace the negative values with 0.
Scenario 1, 3, and 4 are working! But Scenario 2 doesn't work. (I hope I covered all possible scenarios in my examples)
Note: The positive values should never disappear, they can only move down when needed. Only the negative values (below -100) disappear.
These examples should explain it better:
Scenario 1: # This Works
DATA
[[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 1, 3, 1, 0, 0],
[-102, -102, -102, 0, 0],
[ 3, 1, 3, 0, 0]]
EXPECT
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 3, 1, 0, 0],
[3, 1, 3, 0, 0]]
Scenario 2: # Doesn't Work
DATA
[[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 1, 2, 1, 0, 0],
[ 2, 1, 2, 0, 0],
[-103, -103, -103, 0, 0]]
EXPECT
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 1, 0, 0],
[2, 1, 2, 0, 0]]
The Current Output (Incorrect):
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 1, 0, 0],
[2, 1, 2, 0, 0],
[0, 0, 0, 0, 0]]
Scenario 3: # This Works
DATA
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, -101, -101, -101],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
EXPECT
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
Scenario 4: # This Works
DATA
[[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[-101, 2, 2, 3, 4],
[-101, 1, 2, 3, 2],
[-101, 3, 3, 2, 3]]
EXPECT
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 2, 3, 4],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
Here is my code - It's definitely overcomplicated for what I am trying to achieve but I have been stuck on this and can't figure out any alternative. (I can't import any outside function...so no numpy)
def move(data):
# PART 1
'''
Creates a list that contains a tuple (row, coll) of the location where a negative value (> -100) appears on the list.
'''
rows = len(data)
c_count = 4
row_list = []
while c_count >= 0:
for x in range(rows):
if data[x][c_count] < -100:
row_list.append((x, c_count))
c_count -=1
# PART 2
'''
Iterates through the list of values that contain negative value (> -100) and performs the actions listed below.
'''
for x in row_list:
row = x[0]
col = x[1]
try: # If there isn't anything above the negative value (except for 0), make all negative value (>-100) == 0. EXAMPLE (DATA 3)
if data[row-1][col] == 0:
data[row][col] = 0
except(IndexError):
pass
try: # If a row of negative values is between a row on top and bottom that contains possitive values, then merge the values above with the negative values below it. EXAMPLE (DATA 1)
if data[row-1][col] > 0 and data[row+1][col] > 0:
c_count = 4
while c_count >= 0:
count = len(data) - 1
prev = count - 1
while count > 0 and prev >= 0:
if data[count][c_count] < -100:
while prev >= 0 and data[prev][c_count] == 0:
prev -= 1
data[count][c_count] = data[prev][c_count]
data[prev][c_count]= 0
count -= 1
prev -= 1
c_count -= 1
return data
except(IndexError):
pass
try: # If a row of negative values has nothing underneath it (at the bottom) of the list. Then push everything on the top down replacing the negative value. This isn't working!
**SCENARIO 2 Should Have Worked Here**
if data[row-1][col] > 0:
data[row][col] = 0
rows = len(data)
c_count = 4
while c_count >= 0:
for x in range(rows):
if data[x][c_count] > 0:
rows = x
break
last = rows-1
if data[last][c_count] == 0:
while last > 0:
data[last][c_count] = data[last-1][c_count]
last -= 1
data[0][c_count] = 0
c_count -= 1
except(IndexError):
pass
return data
print('Data 1') # This Works
data1 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 3, 1, 0, 0],
[-102, -102, -102, 0, 0],
[3, 1, 3, 0, 0]]
print(data1, 'org')
x = move(data1)
expect1 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 3, 1, 0, 0],
[3, 1, 3, 0, 0]]
print(x, 'sol')
print(expect1, 'expect')
print(data1 == expect1)
print()
print('Data 2') # Doesn't Work
data2 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 1, 0, 0],
[2, 1, 2, 0, 0],
[-103, -103, -103, 0, 0]]
print(data2, 'org')
y = move(data2)
expect2 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 1, 0, 0],
[2, 1, 2, 0, 0]]
print(y,'sol')
print(expect2, 'expect')
print(data2 == expect2)
print()
print('Data 3') # This Works
data3 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, -101, -101, -101],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
print(data3, 'org')
z = move(data3)
expect3 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
print(z,'sol')
print(expect3, 'expect')
print(data3 == expect3)
print()
print('Data 4') # This Works
data4 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[-101, 2, 2, 3, 4],
[-101, 1, 2, 3, 2],
[-101, 3, 3, 2, 3]]
print(data4, 'org')
a = move(data4)
expect4 = [[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 2, 3, 4],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]]
print(a,'sol')
print(expect4, 'expect')
print(data4 == expect4)
I use code from previous question
Python - Shift/Delete Elements in a 2-Dimensional Array
and it gives correct results:
I work with columns separately, not with full rows.
search in column from bottom to top
find negative value
find positive value (bigger then zero) above
if not found then put zero in place of negative
if found then move down all value above
(move above to row, above-1 to row-1, above-2 to row-2, etc.)
.
def move(data):
# work in column, not with full rows
for col in range(len(data)):
# move from bottom to top
for row in range(len(data[0])-1, -1, -1):
# check if negative value
if data[row][col] < 0:
print('debug: negative:', data[row][col])
# find positive value above
above = row-1
while above > -1 and data[above][col] <= 0:
above -= 1
# check if found positive value
if above == -1:
# put zero if not found value above
print('debug: put zero')
data[row][col] = 0
else:
# move down all values above
print('debug: move down', above+1, 'element(s)')
while above > -1:
data[row][col] = data[above][col]
data[above][col] = 0
row -= 1
above -= 1
return data
# --- function to run one scenario, display data and check result ---
def run(data, expect):
print('data:')
print('\n'.join(str(row) for row in data))
print()
result = move(data)
print()
print('result:')
print(result)
print('expect:')
print(expect)
print('expect == result:', expect == result)
print('---')
# --- scenarios ---
def scenario_B1():
DATA = [
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 1, 3, 1, 0, 0],
[-102, -102, -102, 0, 0],
[ 3, 1, 3, 0, 0]
]
EXPECT = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 3, 1, 0, 0],
[3, 1, 3, 0, 0]
]
run(DATA, EXPECT)
def scenario_B2():
DATA = [
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 1, 2, 1, 0, 0],
[ 2, 1, 2, 0, 0],
[-103, -103, -103, 0, 0]
]
EXPECT = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[1, 2, 1, 0, 0],
[2, 1, 2, 0, 0]
]
run(DATA, EXPECT)
def scenario_B3():
DATA = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, -101, -101, -101],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]
]
EXPECT = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]
]
run(DATA, EXPECT)
def scenario_B4():
DATA = [
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[-101, 2, 2, 3, 4],
[-101, 1, 2, 3, 2],
[-101, 3, 3, 2, 3]
]
EXPECT = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 2, 3, 4],
[0, 1, 2, 3, 2],
[0, 3, 3, 2, 3]
]
run(DATA, EXPECT)
# --- start scenarios ---
scenario_B1()
scenario_B2()
scenario_B3()
scenario_B4()
Results:
data:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[1, 3, 1, 0, 0]
[-102, -102, -102, 0, 0]
[3, 1, 3, 0, 0]
debug: negative: -102
debug: move down 3 element(s)
debug: negative: -102
debug: move down 3 element(s)
debug: negative: -102
debug: move down 3 element(s)
result:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 3, 1, 0, 0], [3, 1, 3, 0, 0]]
expect:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 3, 1, 0, 0], [3, 1, 3, 0, 0]]
expect == result: True
---
data:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[1, 2, 1, 0, 0]
[2, 1, 2, 0, 0]
[-103, -103, -103, 0, 0]
debug: negative: -103
debug: move down 4 element(s)
debug: negative: -103
debug: move down 4 element(s)
debug: negative: -103
debug: move down 4 element(s)
result:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 2, 1, 0, 0], [2, 1, 2, 0, 0]]
expect:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 2, 1, 0, 0], [2, 1, 2, 0, 0]]
expect == result: True
---
data:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 2, -101, -101, -101]
[0, 1, 2, 3, 2]
[0, 3, 3, 2, 3]
debug: negative: -101
debug: put zero
debug: negative: -101
debug: put zero
debug: negative: -101
debug: put zero
result:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 1, 2, 3, 2], [0, 3, 3, 2, 3]]
expect:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0], [0, 1, 2, 3, 2], [0, 3, 3, 2, 3]]
expect == result: True
---
data:
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[-101, 2, 2, 3, 4]
[-101, 1, 2, 3, 2]
[-101, 3, 3, 2, 3]
debug: negative: -101
debug: put zero
debug: negative: -101
debug: put zero
debug: negative: -101
debug: put zero
result:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 2, 3, 4], [0, 1, 2, 3, 2], [0, 3, 3, 2, 3]]
expect:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 2, 2, 3, 4], [0, 1, 2, 3, 2], [0, 3, 3, 2, 3]]
expect == result: True
---