【问题标题】:Python rotating the elements inside subarraysPython旋转子数组内的元素
【发布时间】:2020-07-25 06:10:42
【问题描述】:

我正在尝试按给定顺序创建两个子数组,在这种情况下,我有 两个整数 a 和 b a 代表子数组范围的值,b 代表多少次它需要旋转。

我创建了这样的子数组;

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

假设 a10 并且 b1 输出是:

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

但是我怎样才能反转每个子数组b 次?

我想要的输出;

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

【问题讨论】:

标签: python arrays list-comprehension


【解决方案1】:

您可以通过切片来旋转内部列表:

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))

输出:

(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]])

【讨论】:

  • 与在我的回答中使用 deque 方法相比,刚刚做了一些计时。您的解决方案具有几乎相同的执行时间,而且更紧凑。
  • 您好 Mauirce,感谢您的回答,但您的代码总是在 b > 4 时返回 [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]],但这是迄今为止最好的答案,再次感谢!
【解决方案2】:

可以将每个子数组的最后一个元素弹出b次,插入到开头:

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]]

【讨论】:

  • 首先感谢您的友好回答海纳,但如果可能的话,我试图处理列表理解。但是您的代码在所有情况下都能完美运行,谢谢!
【解决方案3】:

您可以使用内置rotate() 函数的双端队列,

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,但就像我在标题中提到的那样,我正在尝试使用一个列表理解,但是您的代码在所有情况下都可以正常工作,再次感谢!
【解决方案4】:

您也可以使用索引。像这样:

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)

输出:

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

编辑

对于b 大于a/2 的边缘情况。像这样使用模数:

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]]

这也可以在 Maurice Meyer 的回答(迄今为止最好)中完成。

【讨论】:

  • 嗨@gnobad,感谢您的友好回答,在您的回答中,当 b > 4 时它总是返回相同的输出,我试图用一个列表理解来做到这一点,再次感谢!
  • 感谢您的意见。我敢肯定,如果您愿意,您可以按大小取模。如果您有兴趣,我可以更新我的答案。虽然,我认为@Maurice-Meyer 在这里有最好的答案。
【解决方案5】:

我也想出了这些解决方案。

具有numpy的滚动功能;

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]]  

使用 numpy 的滚动功能也更简单;

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]] 

如果您不想使用包裹并且您有一点点流血也没关系;

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]] 

【讨论】:

    【解决方案6】:

    如果适用,我建议使用双端队列。 我希望这个列表会更快。

    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])
    

    【讨论】: