8

How would one (efficiently) do the following:

x = np.arange(49)
x2 = np.reshape(x, (7,7))

x2
array([[ 0,  1,  2,  3,  4,  5,  6],
       [ 7,  8,  9, 10, 11, 12, 13],
       [14, 15, 16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25, 26, 27],
       [28, 29, 30, 31, 32, 33, 34],
       [35, 36, 37, 38, 39, 40, 41],
       [42, 43, 44, 45, 46, 47, 48]])

From here I want to roll a couple of things. I want to roll 0,7,14,21 etc so 14 comes to top. Then the same with 4,11,18,25 etc so 39 comes to top.
Result should be:

x2
array([[14,  1,  2,  3, 39,  5,  6],
       [21,  8,  9, 10, 46, 12, 13],
       [28, 15, 16, 17,  4, 19, 20],
       [35, 22, 23, 24, 11, 26, 27],
       [42, 29, 30, 31, 18, 33, 34],
       [ 0, 36, 37, 38, 25, 40, 41],
       [ 7, 43, 44, 45, 32, 47, 48]])

I looked up numpy.roll, here and google but couldn't find how one would do this.
For horizontal rolls, I could do:

np.roll(x2[0], 3, axis=0)

x3
array([4, 5, 6, 0, 1, 2, 3])

But how do I return the full array with this roll change as a new copy?

4 Answers 4

6

Roll with a negative shift:

x2[:, 0] = np.roll(x2[:, 0], -2)

Roll with a positive shift:

x2[:, 4] = np.roll(x2[:, 4], 2)

gives:

>>>x2
array([[14,  1,  2,  3, 39,  5,  6],
       [21,  8,  9, 10, 46, 12, 13],
       [28, 15, 16, 17,  4, 19, 20],
       [35, 22, 23, 24, 11, 26, 27],
       [42, 29, 30, 31, 18, 33, 34],
       [ 0, 36, 37, 38, 25, 40, 41],
       [ 7, 43, 44, 45, 32, 47, 48]])
Sign up to request clarification or add additional context in comments.

Comments

4

Here's a way to roll multiple columns in one go with advanced-indexing -

# Params
cols = [0,4]  # Columns to be rolled
dirn = [2,-2] # Offset with direction as sign

n = x2.shape[0]
x2[:,cols] = x2[np.mod(np.arange(n)[:,None] + dirn,n),cols]

Sample run -

In [45]: x2
Out[45]: 
array([[ 0,  1,  2,  3,  4,  5,  6],
       [ 7,  8,  9, 10, 11, 12, 13],
       [14, 15, 16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25, 26, 27],
       [28, 29, 30, 31, 32, 33, 34],
       [35, 36, 37, 38, 39, 40, 41],
       [42, 43, 44, 45, 46, 47, 48]])

In [46]: cols = [0,4,5]  # Columns to be rolled
    ...: dirn = [2,-2,4] # Offset with direction as sign
    ...: n = x2.shape[0]
    ...: x2[:,cols] = x2[np.mod(np.arange(n)[:,None] + dirn,n),cols]
    ...: 

In [47]: x2  # Three columns rolled
Out[47]: 
array([[14,  1,  2,  3, 39, 33,  6],
       [21,  8,  9, 10, 46, 40, 13],
       [28, 15, 16, 17,  4, 47, 20],
       [35, 22, 23, 24, 11,  5, 27],
       [42, 29, 30, 31, 18, 12, 34],
       [ 0, 36, 37, 38, 25, 19, 41],
       [ 7, 43, 44, 45, 32, 26, 48]])

Comments

0

You have to overwrite the column

e.g.:

x2[:,0] = np.roll(x2[:,0], 3)

Comments

0

See here a useful method for shifting a 2D array in all 4 directions (up, down, left, right):

def image_shift_roll(img, x_shift, y_roll):
    img_roll = img.copy()
    img_roll = np.roll(img_roll, -y_roll, axis = 0)    # Positive y rolls up
    img_roll = np.roll(img_roll, x_roll, axis = 1)     # Positive x rolls right
    return img_roll

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.