Yagiz Degirmenci
Yagiz Degirmenci

Reputation: 20598

Python rotating the elements inside subarrays

I am trying to create two subarrays in given order, in this case i have two integers a and b a represents the value of the subarrays range, and b represents how many times it needs to be rotated.

I created the subarrays like this;

def reorder(a,b):
   return [[i for i in range(0, a//2)]] + [[f for f in range(a//2, a)]]

Imagine a is 10 and b is 1 the output is:

[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]

But how can i reverse each subarrays b times?

The output that i want;

[[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]]

Upvotes: 1

Views: 311

Answers (6)

Yagiz Degirmenci
Yagiz Degirmenci

Reputation: 20598

I also came up with these solutions.

With numpy's roll function;

import numpy as np
def reorder(a, b):
   return [list(np.roll(v,b)) for v in [list(range(a//2)),list(range(a-a//2,a))]]  

In:  reorder(10,9)  
Out: [[1, 2, 3, 4, 0], [6, 7, 8, 9, 5]]  

Also much simpler solution with numpy's roll function;

import numpy as np
def reorder(a, b):
    return np.roll(np.arange(a).reshape(2, -1), b, 1).tolist()

In:  reorder(10,9)  
Out: [[1, 2, 3, 4, 0], [6, 7, 8, 9, 5]] 

If you don't wanna use packages and you are okay with a little bit of eye bleeding;

def reorder(a, b):
   return [list(range(a//2))[-b%(a//2):] + list(range(a//2))[:-b%(a//2)], list(range(a//2, a))[-b%(a//2):] + list(range(a//2, a))[:-b%(a//2)]]

In: reorder(10,9)  
Out: [[1, 2, 3, 4, 0], [6, 7, 8, 9, 5]] 

Upvotes: 1

Maurice Meyer
Maurice Meyer

Reputation: 18106

You can rotate the inner lists by slicing:

def reorder(a,b):
    slicingPosition = a/2 % b
    return [y[-slicingPosition:] + y[:-slicingPosition] for y in [[i for i in range(0, a//2)]] + [[f for f in range(a//2, a)]]]


for x in range(1, 6):
    print(x, '>>', reorder(10, x))

Output:

(1, '>>', [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
(2, '>>', [[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])
(3, '>>', [[3, 4, 0, 1, 2], [8, 9, 5, 6, 7]])
(4, '>>', [[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]])
(5, '>>', [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])

Upvotes: 3

gnodab
gnodab

Reputation: 880

You can use indexing as well. Like so:

def reorder(a, b):
  tmp = [[i for i in range(0, a//2)]] + [[f for f in range(a//2, a)]]
  tmp[0] = tmp[0][-b:] + tmp[0][:-b]
  tmp[1] = tmp[1][-b:] + tmp[1][:-b]
  return tmp

reorder(10, 1)

Output:

[[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]]

Edit

For the edge case where b is greater than a/2. Use the modulo as such:

def reorder(a, b):
  sz = a//2
  r = b%sz
  tmp = [[i for i in range(0, sz)]] + [[f for f in range(sz, a)]]
  tmp[0] = tmp[0][-r:] + tmp[0][:-r]
  tmp[1] = tmp[1][-r:] + tmp[1][:-r]
  return tmp

reorder(10, 7)

[[3, 4, 0, 1, 2], [8, 9, 5, 6, 7]]

This can be done for in Maurice Meyer's answer (best so far) as well.

Upvotes: 1

DrBwts
DrBwts

Reputation: 3657

You can use a double ended que which has a built in rotate() function,

from collections import deque

def reorder(a,b):

   my_arr   = [[i for i in range(0, a//2)]] + [[f for f in range(a//2, a)]]
   first_q  = deque(my_arr[0])
   second_q = deque(my_arr[1])

   first_q.rotate(b)
   second_q.rotate(b)

   return [list(first_q), list(second_q)]


print(reorder(10, 1))

Upvotes: 1

Mensch
Mensch

Reputation: 700

If applicable I'd suggest using deque. I'd expect it to be faster that list.

import collections
def reorder(a,b):
   tmp = [[i for i in range(0, a//2)]] + [[f for f in range(a//2, a)]]

   for i in range(len(tmp)):
     tmp[i] = collections.deque(tmp[i])

     # rotates to right for positive numbers
     tmp[i].rotate(b)

print d
>>> deque([3, 4, 5, 1, 2])

Upvotes: 0

Heiner Früh
Heiner Früh

Reputation: 127

You can pop the last element of each subarray b times and insert it at the beginning:

def reorder(a,b):
    suba = [i for i in range(0, a//2)] 
    subb = [f for f in range(a//2, a)]
    for i in range(b):
        suba = [suba.pop(-1)]+suba
        subb = [subb.pop(-1)]+subb
    return [suba,subb]

In[1]:  reorder(10,1)
Out[1]: [[4, 0, 1, 2, 3], [9, 5, 6, 7, 8]]

Upvotes: 1

Related Questions