파이썬에서 두 개의 발전기(또는 다른 반복 가능한 것)를 결합하는 방법은 무엇입니까?
다음 코드를 변경하고 싶습니다.
for directory, dirs, files in os.walk(directory_1):
do_something()
for directory, dirs, files in os.walk(directory_2):
do_something()
다음 코드로:
for directory, dirs, files in os.walk(directory_1) + os.walk(directory_2):
do_something()
오류가 발생했습니다.
+: 'property' 및 'property'에 대해 지원되지 않는 피연산자 유형
파이썬에서 두 발전기에 가입하는 방법은?
itertools.chain()
해야 합니다.여러 반복 가능한 항목과 각 항목의 산출량은 대략 다음과 같습니다.
def chain(*iterables):
for it in iterables:
for element in it:
yield element
사용 예:
from itertools import chain
g = (c for c in 'ABC') # Dummy generator, just for example
c = chain(g, 'DEF') # Chain the generator and a string
for item in c:
print(item)
출력:
A
B
C
D
E
F
코드의 예:
from itertools import chain
def generator1():
for item in 'abcdef':
yield item
def generator2():
for item in '123456':
yield item
generator3 = chain(generator1(), generator2())
for item in generator3:
print item
Python(3.5 이상)에서는 다음을 수행할 수 있습니다.
def concat(a, b):
yield from a
yield from b
간단한 예:
from itertools import chain
x = iter([1,2,3]) #Create Generator Object (listiterator)
y = iter([3,4,5]) #another one
result = chain(x, y) #Chained x and y
iter tools.chain과 함께.다음과 같은 작업을 수행할 수 있습니다.
def genny(start):
for x in range(start, start+3):
yield x
y = [1, 2]
ab = [o for o in itertools.chain.from_iterable(genny(x) for x in y)]
print(ab)
여기서는 중첩된 생성자 식을 사용하고 있습니다.for
s:
range_a = range(3)
range_b = range(5)
result = (item
for one_range in (range_a, range_b)
for item in one_range)
assert list(result) == [0, 1, 2, 0, 1, 2, 3, 4]
그for ... in ...
왼쪽에서 오른쪽으로 평가됩니다.다음의 식별자for
새 변수를 설정합니다.하는 동안에one_range
다음에 사용되는for ... in ...
,그item
두 번째 것부터 "최종" 할당식에 사용되며, "최종" 할당식에는 (처음에) 하나만 사용됩니다.
관련 질문:어떻게 하면 목록에서 플랫 목록을 만들 수 있습니까?
2020년 업데이트:Python 3 및 Python 2 모두에서 작동합니다.
import itertools
iterA = range(10,15)
iterB = range(15,20)
iterC = range(20,25)
첫 번째 선택지
for i in itertools.chain(iterA, iterB, iterC):
print(i)
# 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
대체 옵션, python 2.6에 도입됨
for i in itertools.chain.from_iterable( [iterA, iterB, iterC] ):
print(i)
# 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
이터툴.체인.from_iterable은 반복 가능한 항목이 있는 경우 유용합니다.예를 들어 다음과 같은 하위 디렉터리별 파일 목록[ ["src/server.py", "src/readme.txt"], ["test/test.py"] ]
.
또한 언팩 연산자를 사용할 수 있습니다.*
:
concat = (*gen1(), *gen2())
참고: '지루하지 않은' 반복 작업에 가장 효율적으로 사용할 수 있습니다.다른 종류의 이해와 함께 사용할 수도 있습니다.제너레이터 콘캣에 대한 선호되는 방법은 @Uduse의 답변을 사용하는 것입니다.
생성기를 별도로 유지하면서 동시에 반복하려면 zip()을 사용할 수 있습니다.
참고: 두 발전기 중 짧은 쪽에서 반복이 멈춥니다.
예:
for (root1, dir1, files1), (root2, dir2, files2) in zip(os.walk(path1), os.walk(path2)):
for file in files1:
#do something with first list of files
for file in files2:
#do something with second list of files
(거부자:Python 3만 해당!)
원하는 구문과 유사한 구문을 가진 것은 스플랫 연산자를 사용하여 두 개의 생성기를 확장하는 것입니다.
for directory, dirs, files in (*os.walk(directory_1), *os.walk(directory_2)):
do_something()
설명:
이것은 효과적으로 두 발전기를 3-튜플의 N-튜플로 단일 레벨 평탄화를 수행합니다.os.walk
다음과 같이 표시됩니다.
((directory1, dirs1, files1), (directory2, dirs2, files2), ...)
그런 다음 for-loop이 이 N-tup을 통해 반복됩니다.
물론 외부 괄호를 괄호로 바꾸기만 하면 N-튜플 대신 3-튜플 목록을 얻을 수 있습니다.
for directory, dirs, files in [*os.walk(directory_1), *os.walk(directory_2)]:
do_something()
이는 다음과 같은 결과를 낳습니다.
[(directory1, dirs1, files1), (directory2, dirs2, files2), ...]
프로:
이 접근 방식의 장점은 어떤 것도 가져올 필요가 없고 코드도 많지 않다는 것입니다.
단점:
단점은 두 개의 제너레이터를 컬렉션에 덤프한 다음 해당 컬렉션을 반복하여 두 개의 패스를 효과적으로 수행하고 잠재적으로 많은 메모리를 사용한다는 것입니다.
생성기(gen1 및 gen2)가 필요하고 두 결과를 모두 요구하는 추가 계산을 수행하려고 합니다.이러한 함수/계산 결과를 맵 방법을 통해 반환할 수 있으며, 이 방법은 루프할 수 있는 생성기를 반환합니다.
이 시나리오에서는 람다 함수를 통해 함수/계산을 구현해야 합니다.까다로운 부분은 지도와 람다 함수 안에서 우리가 하고자 하는 것입니다.
제안된 솔루션의 일반적인 형태:
def function(gen1,gen2):
for item in map(lambda x, y: do_somethin(x,y), gen1, gen2):
yield item
나는 사용자 "wjandrea"의 댓글에서 제안된 것처럼, 가장 좋은 해결책은 다음과 같습니다.
def concat_generators(*gens):
for gen in gens:
yield from gen
그것은 반환된 유형을 바꾸지 않고 정말로 파이썬입니다.
이전과 이후에 knows 디렉토리에서 파일 경로 목록을 가져오려면 다음 작업을 수행할 수 있습니다.
for r,d,f in os.walk(current_dir):
for dir in d:
if dir =='after':
after_dir = os.path.abspath(os.path.join(current_dir, dir))
for r,d,f in os.walk(after_dir):
after_flist.append([os.path.join(r,file)for file in f if file.endswith('json')])
elif dir =='before':
before_dir = os.path.abspath(os.path.join(current_dir, dir))
for r,d,f in os.walk(before_dir):
before_flist.append([os.path.join(r,file)for file in f if file.endswith('json')])
더 나은 답이 있다는 것을 압니다. 이것은 제가 느낀 간단한 코드입니다.
모든 제너레이터를 목록에 넣을 수 있습니다.제너레이터를 결합할 수는 없지만 목록을 결합할 수는 있습니다.단점은 실제로 메모리에 3개의 목록을 만들었다는 것입니다. 하지만 장점은 이것이 매우 읽기 쉽고 가져오기가 필요하지 않으며 한 줄로 된 관용어라는 것입니다.
운영을 위한 솔루션.
for directory, dirs, files in list(os.walk(directory_1)) + list(os.walk(directory_2)):
do_something()
a = range(20)
b = range(10,99,3)
for v in list(a) + list(b):
print(v)
한 번만 수행하면 되고 모듈을 하나 더 가져오지 않으려면 간단한 해결 방법이 있습니다.
그냥 하기:
for dir in directory_1, directory_2:
for directory, dirs, files in os.walk(dir):
do_something()
두 생성기를 모두 "가입"하려면 다음을 수행합니다.
for directory, dirs, files in (
x for osw in [os.walk(directory_1), os.walk(directory_2)]
for x in osw
):
do_something()
언급URL : https://stackoverflow.com/questions/3211041/how-to-join-two-generators-or-other-iterables-in-python
'itsource' 카테고리의 다른 글
git 하위 모듈 업데이트가 'detected submodule: detected in repository: (0) | 2023.07.06 |
---|---|
오류: Firebase 프로젝트 프로젝트 이름을 가져오지 못했습니다.프로젝트가 존재하고 계정에 액세스 권한이 있는지 확인하십시오. (0) | 2023.07.06 |
Get: TypeError: 'dict_values' 개체는 python 3.2.3을 사용할 때 인덱싱을 지원하지 않습니다. (0) | 2023.07.06 |
Firebase : 실시간 데이터베이스와 파일 저장소의 차이점 (0) | 2023.07.06 |
타사 앱 실행 시 LibStatusBar 아이콘이 사라짐 (0) | 2023.07.06 |