1

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)
7
  • can you detail out your example for each iteration... somehow I am not able to figure out what and how you want to achieve the mentioned expected result. Commented Nov 28, 2017 at 7:22
  • I meant to bold the text in my results (had **) instead. Hopefully it's more clear now. My condition 1 is functional but I also need condition 2 to work. So each time I call this, it will shift once towards the end unless their is a value > 0. Hopefully that is more clear. Thanks (: Commented Nov 28, 2017 at 7:43
  • original version is moving in range (first row, last row) (in other words (0, rows)). Correct version should first find positiove value and then star moving in range (0, row_with_positive-1) Commented Nov 28, 2017 at 8:40
  • Thanks for responding. I am still somewhat unsure how this would look like. I basically want it to stop shifting elements when it reaches a positive value. (Like the Condition 2). I will specify the column number, it is [-1] in the above example. Commented Nov 28, 2017 at 8:47
  • @furas If you have time. A code snippet (like you provided previously) would be much appreciated. Thanks (: Commented Nov 28, 2017 at 8:49

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks so much! Will implement this in the morning and hopefully it will work. The last line doesn’t necessarily have to be 0 in this version. It can also be a positive value (3) so I am assuming I don’t need that if statement anymore since the program will stop at the line before it?
if data[last][-1] == 0 checks if you have 0 before 3 (first positive value). If there is ie. -4 then there is no need to move. Or maybe you have to move even when there is -4 ? Then you can remove this if.
In that case the 0 stays. I guess I got confused. Thanks
use print() inside function to see what's going on in code -
0

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]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.