Reputation: 163
Given this 2D Array -
[[0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3], [0, 0, 0]]
How can I code something in Python that shifts once to the end each time it's called? However, it has to stop if it reaches a positive value.
So I get something like this
[[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]]
This is what I have. It works for condition 1 but it does not work for condition 2. What can I tweak so condition 2 also works?
# Condition 1 - Works
data = [[0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0], [0, 0, 0]]
expected = [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0]] # My Results.
# Condition 2 - Does Not Work
data = [[0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3], [0, 0, 0]]
expected = [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]] # This is what I want to get. (But it doesn't work)
rows = len(data)
if data[-1][-1] == 0:
count = rows-1
while count > 0:
data[count][-1] = data[count-1][-1]
count -= 1
data[0][-1] = 0
print(data)
print(expected)
This is what I am getting currently. I want to get the expected for Condition 2 listed in the code snipped above.:
Condition 2 Result: [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3]]
Thanks
Update @Furas: Something like this to find the positive value location?
possitive_value = []
for i in range(len(data)):
if data[i][-1] > 0:
possitive_value.append(i, -1)
Upvotes: 1
Views: 4241
Reputation: 764
Here's a variation, a function that can be called and will shift data by one every time. I wasn't entirely clear from your question if this was the behavior you wanted.
import numpy as np
def shift_data(data):
ele_idx = [i for i,x in enumerate(data) if x != [0,0,0]]
zero_idx = [i for i,x in enumerate(data) if x == [0,0,0] and i != 0]
if max(np.diff(ele_idx)) == 1 or max(np.diff([i for i,x in enumerate(data) if x == [0,0,0]])) == 1:#things are consecutive
data.insert(0,data.pop(-1))
else:
tt = [l for l in data[ele_idx[0]:zero_idx[0]+1]]
tt.insert(0,tt.pop(-1))
data = data[:ele_idx[0]] + tt + data[zero_idx[0]+1:]
return data
data = [[0, 0, -1], [0, 0, 0], [0, 0, -2], [0, 0, 0], [0, 0, 3]]
print(data)
for _ in range(0,6):
data = shift_data(data)
print(data)
This code outputs:
[[0, 0, -1], [0, 0, 0], [0, 0, -2], [0, 0, 0], [0, 0, 3]]
[[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3]]
[[0, 0, 0], [0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3]]
[[0, 0, 3], [0, 0, 0], [0, 0, 0], [0, 0, -1], [0, 0, -2]]
[[0, 0, -2], [0, 0, 3], [0, 0, 0], [0, 0, 0], [0, 0, -1]]
[[0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]]
Upvotes: 0
Reputation: 142661
I think you have to find first positive value and use its position as rows
EDIT: I changed name count
to last
to make it more readable
# --- function ---
def move(data):
rows = len(data)
# - find positive -
for x in range(rows):
if data[x][-1] > 0:
rows = x # use its position as `rows`
break # don't seach other positiove values
# - star moving -
# set "last" checked row
last = rows-1
# check "last" row
if data[last][-1] == 0:
# move previous values
while last > 0:
data[last][-1] = data[last-1][-1]
last -= 1
# put 0 in first place
data[0][-1] = 0
# --- tests ---
examples = [
{
# Condition 1 - Works
'data': [[0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0], [0, 0, 0]],
'expected': [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0]], # My Results.
},
{
# Condition 2 - Works
'data': [[0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3], [0, 0, 0]],
'expected': [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]], # This is what I want to get. (But it doesn't work)
}
]
for example in examples:
data = example['data']
expected = example['expected']
print(' before:', data)
move(data)
print(' after:', data)
print('expected:', expected)
print(' correct:', data == expected)
print('---')
Result:
before: [[0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0], [0, 0, 0]]
after: [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0]]
expected: [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, -3], [0, 0, 0]]
correct: True
---
before: [[0, 0, -1], [0, 0, -2], [0, 0, 0], [0, 0, 3], [0, 0, 0]]
after: [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]]
expected: [[0, 0, 0], [0, 0, -1], [0, 0, -2], [0, 0, 3], [0, 0, 0]]
correct: True
---
EDIT:
BTW: instead of while
you can use for
with reversed range()
if it makes it more readable
def move(data):
rows = len(data)
# - find positive -
for x in range(rows):
if data[x][-1] > 0:
rows = x # use its position as `rows`
break # don't seach other positiove values
# - star moving -
# set "last" checked row
last = rows-1
# check "last" row
if data[last][-1] == 0:
# move previous values
for pos in range(last, 0, -1): # range with reversed order
data[pos][-1] = data[pos-1][-1]
# put 0 in first place
data[0][-1] = 0
BTW: both versions move items in original data ("in-place"
) so they don't need return data
.
Upvotes: 2