<p>如果你有足够的内存空间:让<code>itertools.product</code>完成这项艰苦的工作,并使用<code>zip</code>来切换轴。在</p>
<pre><code>import itertools
def product(shape, axes):
prod_trans = tuple(zip(*itertools.product(*(range(shape[axis]) for axis in axes))))
prod_trans_ordered = [None] * len(axes)
for i, axis in enumerate(axes):
prod_trans_ordered[axis] = prod_trans[i]
return zip(*prod_trans_ordered)
</code></pre>
<p>小测试:</p>
^{2}$
<p>如果没有太多的产品,以上版本是快速的。对于<em>大的</em>结果集,下面的方法更快,但是。。。使用<code>eval</code>(尽管以一种相当安全的方式):</p>
<pre><code>def product(shape, axes):
d = dict(("r%i" % axis, range(shape[axis])) for axis in axes)
text_tuple = "".join("x%i, " % i for i in range(len(axes)))
text_for = " ".join("for x%i in r%i" % (axis, axis) for axis in axes)
return eval("((%s) %s)" % (text_tuple, text_for), d)
</code></pre>
<p><strong>编辑:</strong>如果您不仅要更改迭代的顺序,还需要更改形状(如OP的示例中所示),则需要进行小的更改:</p>
<pre><code>import itertools
def product(shape, axes):
prod_trans = tuple(zip(*itertools.product(*(range(s) for s in shape))))
prod_trans_ordered = [None] * len(axes)
for i, axis in enumerate(axes):
prod_trans_ordered[axis] = prod_trans[i]
return zip(*prod_trans_ordered)
</code></pre>
<p>以及<code>eval</code>版本:</p>
<pre><code>def product(shape, axes):
d = dict(("r%i" % axis, range(s)) for axis, s in zip(axes, shape))
text_tuple = "".join("x%i, " % i for i in range(len(axes)))
text_for = " ".join("for x%i in r%i" % (axis, axis) for axis in axes)
return eval("((%s) %s)" % (text_tuple, text_for), d)
</code></pre>
<p>测试:</p>
<pre><code>>>> print(*product((2, 2, 4), (1, 2, 0)))
(0, 0, 0) (1, 0, 0) (2, 0, 0) (3, 0, 0) (0, 0, 1) (1, 0, 1) (2, 0, 1) (3, 0, 1) (0, 1, 0) (1, 1, 0) (2, 1, 0) (3, 1, 0) (0, 1, 1) (1, 1, 1) (2, 1, 1) (3, 1, 1)
</code></pre>