0

I am working with numpy arrays and and I would like to move a certain value located at certain index by 2 positions on the right while shifting the others element involved on the left by one position each. To be more precise, here below is what I would like to achieve:

from:

     start = [0., 1., 2.],
             [0., 0., 0.],
             [5., 0., 1.]

to:

       end = [1., 2., 0.],
             [0., 0., 0.],
             [5., 0., 1.]

As you can see from the first row, 0 has been moved by two position on the right and 1 and 2 by one position on the left. So far, I succeded by moving an element by one position and moving the other by defining:

def right_move(arr, index, n_steps:int):


   row = index[0]
   col = index[1]

   try:
       arr[row,col], arr[row, col + n_steps] = arr[row, col + n_steps], arr[row, col]

   except:
       pass

   return arr

where n_steps=1. If I input n_steps=2, it won't work since the element in the middle of the swapping remain unchanged.

Can someone help me? Other easier solution are more then welcome!

Thanks

1

2 Answers 2

1

You can use numpy.roll:

import numpy as np

arr = np.array([[0., 1., 2.],
                [0., 0., 0.],
                [5., 0., 1.]])
arr[0] = np.roll(arr[0], 2)
arr
# output:
# [[1., 2., 0.],
#  [0., 0., 0.],
#  [5., 0., 1.]]
Sign up to request clarification or add additional context in comments.

Comments

0

It is supposed the functionality of np.roll. However, np.roll doesn't allow roll on individual row. It piqued my interest to implement a function using as_strided to extend this functionality to np.roll

from numpy.lib.stride_tricks import as_strided

def custom_roll(arr, r_tup):
    m = np.asarray(r_tup)
    arr_roll = arr[:, [*range(arr.shape[1]),*range(arr.shape[1]-1)]].copy() #need `copy`
    strd_0, strd_1 = arr_roll.strides
    n = arr.shape[1]
    result = as_strided(arr_roll, (*arr.shape, n), (strd_0 ,strd_1, strd_1))

    return result[np.arange(arr.shape[0]), (n-m)%n]

Just passing a tuple indicate number of steps for each row. In your case, it rolls only row 0 either 2 positions forward or -1 position backward. so the tuple is (2,0,0) or (-1,0,0)

start = np.array([[0., 1., 2.],
                  [0., 0., 0.],
                  [5., 0., 1.])

out = custom_roll(start, (2,0,0))

Out[780]:
array([[1., 2., 0.],
       [0., 0., 0.],
       [5., 0., 1.]])

Or

out = custom_roll(start, (-1,0,0))

Out[782]:
array([[1., 2., 0.],
       [0., 0., 0.],
       [5., 0., 1.]])

Roll first and last row: (2,0,2)

out =  custom_roll(start, (2,0,2))

Out[784]:
array([[1., 2., 0.],
       [0., 0., 0.],
       [0., 1., 5.]])

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.