web-dev-qa-db-ja.com

多次元範囲のPython range(n)と同等のものはありますか?

Pythonでは、range(3)は[0,1,2]を返します。多次元範囲に相当するものはありますか?

range((3,2)) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]

したがって、たとえば、タイルベースのゲームで長方形領域のタイルをループすることは、次のように書くことができます。

for x,y in range((3,2)):

実装を求めているのではないことに注意してください。これが認識されたパターンであるかどうか、およびPythonに組み込み関数があるかどうか、または標準/共通ライブラリかどうかを知りたいです。

50
MaiaVictor

Numpyでは numpy.ndindexnumpy.ndenumerate

例えば。

import numpy as np
for x, y in np.ndindex((3,2)):
    print x, y

これにより、

0 0
0 1
1 0
1 1
2 0
2 1
62
Joe Kington

itertools.product()を使用できます:

_>>> import itertools
>>> for (i,j,k) in itertools.product(xrange(3),xrange(3),xrange(3)):
...     print i,j,k
_

複数のxrange()ステートメントの繰り返しは、10次元のループまたは同様に馬鹿げたものにスケールアップしたい場合は、次のように表現できます。

_>>> for combination in itertools.product( xrange(3), repeat=10 ):
...     print combination
_

_(0,0,0,0,0,0,0,0,0,0)_から_(2,2,2,2,2,2,2,2,2,2)_まで、10個の変数をループします。


一般的にitertoolsはめちゃくちゃ素晴らしいモジュールです。正規表現が「プレーンな」文字列メソッドよりもはるかに表現力が高いのと同じように、itertoolsは複雑なループを表現する非常にエレガントな方法です。 itertoolsモジュールのドキュメントを読むのはあなた自身の責任です これはあなたの人生をより楽しくします。

37
Li-aung Yip

これには実際には簡単な構文があります。 2つのforsが必要です。

>>> [(x,y) for x in range(3) for y in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
22
dhg

つまり、2つのリストの デカルト積 です。

import itertools
for element in itertools.product(range(3),range(2)):
    print element

この出力を与えます:

(0, 0)
(0, 1)
(1, 0)
(1, 1)
(2, 0)
(2, 1)
6
0x90

productモジュールのitertoolsを使用できます。

itertools.product(range(3), range(2))
3

numpy.meshgrid

http://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.meshgrid.html

これにより、メッシュ/グリッドの各位置でのXおよびYグリッド値が得られます。それからあなたは次のようなことをすることができます:

import numpy as np
X,Y = np.meshgrid(xrange(3),xrange(2))
Zip(X.ravel(),Y.ravel()) 
#[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]

または

Zip(X.ravel(order='F'),Y.ravel(order='F')) 
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
3
JoshAdel

Numpyのndindex()は、指定した例では機能しますが、すべてのユースケースに対応しているわけではありません。任意のstartstop、およびstepの両方を許可するPythonの組み込みrange()とは異なり、numpyのnp.ndindex()は、 stop。 (startは_(0,0,...)_であると推定され、stepは_(1,1,...)_です。)

これは、組み込みのrange()関数のように機能する実装です。つまり、任意のstart/stop/step引数を許可しますが、単なる整数の代わりにtuplesで機能します。

_import sys
from itertools import product, starmap

# Python 2/3 compatibility
if sys.version_info.major < 3:
    from itertools import izip
else:
    izip = Zip
    xrange = range

def ndrange(start, stop=None, step=None):
    if stop is None:
        stop = start
        start = (0,)*len(stop)

    if step is None:
        step = (1,)*len(stop)

    assert len(start) == len(stop) == len(step)

    for index in product(*starmap(xrange, izip(start, stop, step))):
        yield index
_

例:

_In [7]: for index in ndrange((1,2,3), (10,20,30), step=(5,10,15)):
   ...:     print(index)
   ...:
(1, 2, 3)
(1, 2, 18)
(1, 12, 3)
(1, 12, 18)
(6, 2, 3)
(6, 2, 18)
(6, 12, 3)
(6, 12, 18)
_
1
Stuart Berg