1

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]]
Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85

6 Answers6

3

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]])
Maurice Meyer
  • 17,279
  • 4
  • 30
  • 47
  • just done some timings compared with using the `deque` method in my answer. Your solution has pretty much the same execution time with added bonus of being more compact. – DrBwts Jun 01 '20 at 15:38
  • Hello Mauirce, thanks for your answer, but your code always returns `[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]` when `b > 4` but this is the best answer so far, thanks again! – Yagiz Degirmenci Jun 01 '20 at 15:48
1

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]]
Heiner Früh
  • 127
  • 5
  • First of all thanks for your kind answer Heiner, but i was trying to do with list comprehension, if possible one liner. but your code works perfectly in all cases, thanks! – Yagiz Degirmenci Jun 01 '20 at 15:44
1

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.

Community
  • 1
  • 1
gnodab
  • 850
  • 6
  • 15
  • Hi @gnobad, thanks for your kind answer, in your answer it always returns the same output when b > 4, and i was trying to do it with one list comprehension, thanks again! – Yagiz Degirmenci Jun 01 '20 at 15:42
  • Thanks for the input. I'm sure you could just modulo by the size if you'd like. I can update my answer if your interested. Although, I think @Maurice-Meyer has the best answer here. – gnodab Jun 01 '20 at 15:50
1

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))
DrBwts
  • 3,470
  • 6
  • 38
  • 62
  • Thanks for your kind answer @DrBwts but like i mentioned in the title, i'm trying to do with one list comprehension, but your code works fine in all cases, thanks again! – Yagiz Degirmenci Jun 01 '20 at 15:54
1

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]] 
Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
0

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])
Mensch
  • 670
  • 7
  • 16