파이썬에서 for 루프 피라미드를 더 간결하게 만들려면 어떻게해야합니까?
이 질문에 이미 답변이 있습니다.
- 파이썬 중첩 반복 관용구 4 답변
견고한 역학에서 저는 종종 Python을 사용하고 다음과 같은 코드를 작성합니다.
for i in range(3):
for j in range(3):
for k in range(3):
for l in range(3):
# do stuff
이 작업을 자주 수행하므로 더 간결한 방법이 있는지 궁금합니다. 현재 코드의 단점은 PEP8
다음 과 같습니다.을 준수하면 줄당 79 자 제한을 초과 할 수 없으며, 특히 이것이 다시 클래스 함수에있는 경우에는 너무 많은 공간이 남아 있지 않습니다.
수행하려는 작업에 따라 itertools
모듈을 사용하여 for
루프 (또는 zip
) 를 최소화 할 수 있습니다 .이 경우 itertools.product
4 개의 루프로 수행 한 작업을 생성합니다.
>>> list(product(range(3),repeat=4))
[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 1, 0), (0, 0, 1, 1),
(0, 0, 1, 2), (0, 0, 2, 0), (0, 0, 2, 1), (0, 0, 2, 2), (0, 1, 0, 0),
(0, 1, 0, 1), (0, 1, 0, 2), (0, 1, 1, 0), (0, 1, 1, 1), (0, 1, 1, 2),
(0, 1, 2, 0), (0, 1, 2, 1), (0, 1, 2, 2), (0, 2, 0, 0), (0, 2, 0, 1),
(0, 2, 0, 2), (0, 2, 1, 0), (0, 2, 1, 1), (0, 2, 1, 2), (0, 2, 2, 0),
(0, 2, 2, 1), (0, 2, 2, 2), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 0, 2),
(1, 0, 1, 0), (1, 0, 1, 1), (1, 0, 1, 2), (1, 0, 2, 0), (1, 0, 2, 1),
(1, 0, 2, 2), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 0, 2), (1, 1, 1, 0),
(1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 2, 0), (1, 1, 2, 1), (1, 1, 2, 2),
(1, 2, 0, 0), (1, 2, 0, 1), (1, 2, 0, 2), (1, 2, 1, 0), (1, 2, 1, 1),
(1, 2, 1, 2), (1, 2, 2, 0), (1, 2, 2, 1), (1, 2, 2, 2), (2, 0, 0, 0),
(2, 0, 0, 1), (2, 0, 0, 2), (2, 0, 1, 0), (2, 0, 1, 1), (2, 0, 1, 2),
(2, 0, 2, 0), (2, 0, 2, 1), (2, 0, 2, 2), (2, 1, 0, 0), (2, 1, 0, 1),
(2, 1, 0, 2), (2, 1, 1, 0), (2, 1, 1, 1), (2, 1, 1, 2), (2, 1, 2, 0),
(2, 1, 2, 1), (2, 1, 2, 2), (2, 2, 0, 0), (2, 2, 0, 1), (2, 2, 0, 2),
(2, 2, 1, 0), (2, 2, 1, 1), (2, 2, 1, 2), (2, 2, 2, 0), (2, 2, 2, 1),
(2, 2, 2, 2)]
그리고 코드에서 다음을 수행 할 수 있습니다.
for i,j,k,l in product(range(3),repeat=4):
#do stuff
이 함수는 실제 구현이 메모리에 중간 결과를 생성하지 않는다는 점을 제외하고 다음 코드와 동일합니다.
def product(*args, **kwds): # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 pools = map(tuple, args) * kwds.get('repeat', 1) result = [[]] for pool in pools: result = [x+[y] for x in result for y in pool] for prod in result: yield tuple(prod)
편집 : @ PeterE가 주석에서 말했듯 product()
이 범위의 길이가 다른 경우에도 사용할 수 있습니다.
product(range(3),range(4),['a','b','c'] ,some_other_iterable)
사용하는 아이디어 itertools.product
는 좋은 것입니다. 다양한 크기의 범위를 지원하는보다 일반적인 접근 방식은 다음과 같습니다.
from itertools import product
def product_of_ranges(*ns):
for t in product(*map(range, ns)):
yield t
for i, j, k in product_of_ranges(4, 2, 3):
# do stuff
생성기 함수가 필요하기 때문에 더 간결하지는 않지만 적어도 PEP8에 신경 쓰지 않을 것입니다.
def tup4(n):
for i in range(n):
for j in range(n):
for k in range(n):
for l in range(n):
yield (i, j, k, l)
for (i, j, k, l) in tup4(3):
# do your stuff
(python 2.x 에서는 생성기 함수 xrange
대신 사용해야 range
합니다)
편집하다:
위의 방법은 피라미드의 깊이를 알면 괜찮을 것입니다. 그러나 외부 모듈없이 일반 생성기를 만들 수도 있습니다.
def tup(n, m):
""" Generate all different tuples of size n consisting of integers < m """
l = [ 0 for i in range(n)]
def step(i):
if i == n : raise StopIteration()
l[i] += 1
if l[i] == m:
l[i] = 0
step(i+ 1)
while True:
yield tuple(l)
step(0)
for (l, k, j, i) in tup(4, 3):
# do your stuff
( (l, k, j, i)
위의 생성기에서 첫 번째 인덱스가 먼저 달라지기 때문에 사용했습니다 )
This is equivalent:
for c in range(3**4):
i = c // 3**3 % 3
j = c // 3**2 % 3
k = c // 3**1 % 3
l = c // 3**0 % 3
print(i,j,k,l)
If you're doing this all the time, consider using a general generator for it:
def nestedLoop(n, l):
return ((tuple((c//l**x%l for x in range(n-1,-1,-1)))) for c in range(l**n))
for (a,b,c,d) in nestedLoop(4,3):
print(a,b,c,d)
'Program Tip' 카테고리의 다른 글
사전이 목록보다 훨씬 빠른 이유는 무엇입니까? (0) | 2020.11.26 |
---|---|
모델을 통해 입력 자리 표시 자의 값을 변경 하시겠습니까? (0) | 2020.11.26 |
문장에있는 토큰의 word2vec에서 문장에 대한 벡터를 얻는 방법 (0) | 2020.11.26 |
Swift XCTest UI에서 테스트 사이에 앱을 재설정하는 방법이 있습니까? (0) | 2020.11.26 |
다른 유형에 대한 반복 (0) | 2020.11.26 |