2

Shift the items in the given array, by some number of times, as shown in the below examples;

array = [1, 2 ,3 , 4, 5, 6]
k1 = 2
k2 = -3
k3 = 20

test1:
cirShift(array, k1)
Result: [5, 6, 1, 2, 3, 4]

test2:
cirShift(array, k2)
Result: [4, 5, 6, 1, 2, 3]

test3:
cirShift(array, k3)
Result: [5, 6, 1, 2, 3, 4]

I have used the below to achieve the right-rotate a list by k positions;

def rightRotateByOne(A):
    Fin= A[-1]
    for i in reversed(range(len(A) - 1)):
        A[i + 1] = A[i]
    A[0] = Fin
 
def rightRotate(A, k):
    if k < 0 or k >= len(A):
        return
    for i in range(k):
        rightRotateByOne(A)
 
if __name__ == '__main__':
    A = [1, 2, 3, 4, 5, 6, 7]
    k = 3
    rightRotate(A, k)
    print(A)

As of now, able to obtain results for test1 but would like to achieve the test2 and test3

Wolf
  • 116
  • 9

3 Answers3

3

Even easier, split the array in half given the boundary, swap and glue back:

def cirShift(a, shift):
    if not shift or not a:
        return a
    return a[-shift%len(a):] + a[:-shift%len(a)]

Courtesy of @KellyBundy, a short-circut one-liner:

def cirShift(a, shift):
    return a and a[-shift%len(a):] + a[:-shift%len(a)]        
Marat
  • 15,215
  • 2
  • 39
  • 48
  • 1
    It also fails for, say, a 6-element list and -83 shifts. – ophact Dec 21 '21 at 04:50
  • @KellyBundy thanks for pointing this out. The fix is pretty trivial, updated the answer – Marat Dec 21 '21 at 05:20
  • @KellyBundy fixed that, too; unfortunately, it was a choice between a really ugly one-liner or an extra `if` – Marat Dec 21 '21 at 05:26
  • Could've inserted `a and` before the normal result. But the `if` might be better if some day you do decide to compute the index only once, beforehand. – Kelly Bundy Dec 21 '21 at 05:32
  • Btw I forgot the empty case as well, saw it pointed out in one of the questions that of course already exist for this problem. – Kelly Bundy Dec 21 '21 at 05:35
2

I think this question may be an exercise in self learning ('how to do X using just python'), so my answer is auxiliary, but you can always use np.roll():

#test 1
import numpy as np
a = [1, 2 ,3, 4, 5, 6]
np.roll(a, 2)

gives output

[5, 6, 1, 2, 3, 4]

and

#test 2
np.roll(a, -2)

gives output

[3, 4, 5, 6, 1, 2]

Even if you give a number that is larger than the array size, it handles the overflow:

#test 3
np.roll(a, 10)

gives output

[3, 4, 5, 6, 1, 2]

Rolling also works in multiple dimension arrays and across specified axes, which is pretty neat.

PeptideWitch
  • 2,239
  • 14
  • 30
1
def shift(l, shift_t):
 r = [*l]
 for n in range(abs(shift_t)):
  if shift_t < 0:
   r = r[1:] + [r[0]]
  else:
   r = [r[-1]] + r[:-1]
 return r

The key is to take one item of the list and place it on the opposite side, which is essentially all that shifting is doing. If you shift negative, you put the first one at the end, and if you shift positive, you put the last one at the beginning.

ophact
  • 126
  • 5