遍历动态数量的 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.transpose
和 reshaping
的 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)的主要内容,如果未能解决你的问题,请参考以下文章