遍历动态数量的 for 循环(Python)

Posted

技术标签:

【中文标题】遍历动态数量的 for 循环(Python)【英文标题】:Iterate through a dynamic number of for loops (Python) 【发布时间】:2016-06-30 23:12:27 【问题描述】:

我正在使用 python 对一些数字进行排序。我想创建一个函数,允许我输入一个值(4、8、16、32、64 等),创建一个数字数组,并重新排列它们的顺序。

我添加了详细说明如何确定 value = 4 和 8 的序列的数字。

对于 value = 4,数组 (x = [0, 1, 2, 3]) 应分成两部分([0,1] 和 [2,3]),然后根据每个数组中的第一个数字组合数组([0, 2 ,1 ,3])。

对于 value = 8,数组 (x = [0, 1, 2, 3, 4, 5, 6, 7]) 应该分成两个([0, 1, 2, 3] 和 [4, 5] , 6, 7])。两个数组都应该再次分成两部分([0, 1, 2, 3] 分为 [0,1] 和 [2,3] 和 [4, 5, 6, 7] 分为 [4,5] 和 [6, 7])。然后根据每个数组中的第一个数字和第二组数组的顺序([0, 4, 2, 6, 1, 5, 3, 7])组合数组。

我不知道如何处理递归(动态嵌套的 for 循环)。我正在尝试遍历通过拆分数组创建的每个分支。我研究了 itertools 和递归(Function with varying number of For Loops (python)),但我无法让它工作。下面,我添加了代码来说明我迄今为止的方法。

非常感谢任何帮助。我也愿意接受其他想法来确定顺序。

我正在使用 python 2.7.6 和 numpy。

代码:

import numpy
value = 4
a = []
x = numpy.arange(value)
y = numpy.array_split(x, 2)
for i in range(2):
    for j in y:
        a.append(j.tolist()[i])
print(a)

输出:

[0, 2, 1, 3]

代码:

import numpy
value = 8
a = []
x = numpy.arange(value)
y = numpy.array_split(x, 2)
for i in range(2):
    for h in range(2):
        for j in y:
        z = numpy.array_split(j, 2)
                a.append(z[h][i])
    print(a)

输出:

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

value = 16 的输出应该是 [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11 ,7 15]。

【问题讨论】:

你需要 numpy 的解决方案吗?我认为这可以用普通的 python 完成 我想说的是,您需要采用二进制形式的数字并按反字母顺序对它们进行排序 【参考方案1】:

这是使用 np.transposereshaping 的 NumPythonic 方式 -

def seq_pow2(N):
    shp = 2*np.ones(np.log2(N),dtype=int)
    return np.arange(N).reshape(shp).transpose(np.arange(len(shp))[::-1]).ravel()

请注意.transpose(np.arange(len(shp))[::-1] 会简化为.T,所以我们会有一个简化版本 -

def seq_pow2(N):
    shp = 2*np.ones(np.log2(N),dtype=int)
    return np.arange(N).reshape(shp).T.ravel()

您可以通过在fortran.ravel('F') 中执行ravel/flattening 中的列主要排序来进一步简化和完全替换转置,最终引导我们到-

def seq_pow2(N):
    shp = 2*np.ones(np.log2(N),dtype=int)
    return np.arange(N).reshape(shp).ravel('F')

示例运行 -

In [43]: seq_pow2(4)
Out[43]: array([0, 2, 1, 3])

In [44]: seq_pow2(8)
Out[44]: array([0, 4, 2, 6, 1, 5, 3, 7])

In [45]: seq_pow2(16)
Out[45]: array([ 0,  8,  4, 12,  2, 10,  6, 14,  1,  9,  5, 13,  3, 11,  7, 15])

【讨论】:

【参考方案2】:

python 递归版本,为清楚起见:

def rec(n):
    if n==1 : return [0]
    l=[0]*n
    l[::2]=rec(n//2)
    for i in range (0,n,2) : l[i+1]=l[i]+n//2
    return l

In [6]: rec(16)
Out[6]: [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

或者,观察结果的二进制表示,一个 numpy 解决方案:

def rearange(N):
    u=2**arange(N.bit_length()-1)
    v=arange(N)
    bits= u[None,:] & v[:,None]
    return sum(bits*u[::-1],1)

【讨论】:

【参考方案3】:

最简单的方法是使用 for 循环,而是使用 numpy 进行一些数组操作。

N = 8
pow2 = np.log2(N)
out = np.arange(N).reshape([2]*pow2).transpose(np.arange(pow2)[::-1]).flatten()   

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

它的作用是将x 重塑为n 维数组,其中n 是2 的幂,对应于x 的长度。经过这个reshape之后,每个维度的长度都是2。然后我们把所有维度都倒过来,然后展平得到你想要的数组。

编辑

这是与Divakar's Solution 类似的方法,他最终做得更简洁,但我将把它留在这里以供后代使用。

【讨论】:

以上是关于遍历动态数量的 for 循环(Python)的主要内容,如果未能解决你的问题,请参考以下文章

Python顶层for循环只运行一次而不是遍历列表

Python:动态嵌套for循环,每个循环具有不同的范围

在JavaScript循环语句中,for 和for.in 循环哪个效率更高

Python 3.5 遍历字典列表

怎样用for循环动态遍历json数组

python 利用 for ... else 跳出双层嵌套循环