생성기 / 반복자에서 항목 수를 계산하는 가장 짧은 방법은 무엇입니까?
요소 자체를 신경 쓰지 않고 반복 가능한 항목의 수를 그것을 얻을 비단뱀적인 방법은 무엇입니까? 지금은
def ilen(it):
return sum(itertools.imap(lambda _: 1, it)) # or just map in Python 3
나는 그것이 lambda
바로 lambda _: 1
예쁘지 않다는 것을 이해 합니다.
(이의 사용 사례는 정규식과 일치하는 텍스트 파일의 줄 수를 계산하는 것 grep -c
입니다.)
일반적인 방법은
sum(1 for i in it)
더 큰 입력에 대한 스왑 스 래싱 및 재 할당 오버 헤드를 방지하기 위해 sum(1 for i in it)
고정 메모리 오버 헤드 동작 (과 달리 len(list(it))
)을 유지하면서 iterable이 길 수있을 때보 다 의미있게 더 빠른 방법 (이터 러블이 짧을 때 의미있게 느리지 발생 ) :
# On Python 2 only, get zip that lazily generates results instead of returning list
from future_builtins import zip
from collections import deque
from itertools import count
def ilen(it):
# Make a stateful counting iterator
cnt = count()
# zip it with the input iterator, then drain until input exhausted at C level
deque(zip(it, cnt), 0) # cnt must be second zip arg to avoid advancing too far
# Since count 0 based, the next value is the count
return next(cnt)
매입 len(list(it))
그 CPython의 C에 코드의 반복 수행 ( deque
, count
및 zip
모든 C로 구현 됨); 루프 당 바이트 코드 실행을 피하는 것이 일반적으로 CPython 성능의 핵심입니다.
성능을 비교하기위한 공정한 테스트 케이스를 찾는 것은 놀랍도록 어렵습니다 ( 임의의 입력 반복 가능에 사용할 수없는 것 같은 list
치트 __length_hint__
, 종종 itertools
제공하지 않는 함수 __length_hint__
에는 값이 각 루프에서 반환 될 때 더 빠른 작동하는 특수 작동 모드) 가 있습니다) 다음 값이있는 요청하기 전에 해제 해제 deque
와 함께 maxlen=0
할 것입니다). 사용한 테스트 케이스 내가는 입력 입력을 받아 특별한 itertools
반환 컨테이너 최적화 가없는 C 생성기를 반환 레벨하는 생성기 함수를 만들 거나 __length_hint__
파이썬 3.3을 사용하는 것입니다 yield from
.
def no_opt_iter(it):
yield from it
그런 다음 ipython
%timeit
매직을 사용 합니다 (100을 다른 상수로 대체).
>>> %%timeit -r5 fakeinput = (0,) * 100
... ilen(no_opt_iter(fakeinput))
입력이 len(list(it))
메모리 문제를 유발할 만큼 충분히 크지 않은 경우 Python 3.5 x64를 실행하는 Linux 상자에서 내 솔루션은 def ilen(it): return len(list(it))
입력 길이에 관계없이.
가장 작은 입력의 경우 deque
/ zip
/ count
/ 호출하는 설정 비용 next
은 def ilen(it): sum(1 for x in it)
(길이 0 입력의 경우 내 컴퓨터에서 약 200ns 더 많은, 간단한 sum
접근 방식에 비해 33 % 증가) 이 방법보다 무한히 더 오래 있습니다. 더 긴 입력, 추가 요소 당 약 절반의 시간으로 실행됩니다. 길이 5 입력의 경우 비용은 동일하며 길이 50-100 범위의 어딘가에서는 실제 작업에 초기 오버 헤드가 눈에 많이 지 연습합니다. sum
접근 방식은 두 배 오래 전시합니다.
기본적으로 메모리 사용이 중요하거나 입력에 크기가없고 간결함보다 속도가 더 중요하다면 솔루션을 사용하십시오. 입력이 제한되고 작은 경우 len(list(it))
아마도 가장 좋을 제한, 제한이 없지만 단순성 / 간결성이 중요하다면 sum(1 for x in it)
.
짧은 방법은 다음과 가변합니다.
def ilen(it):
return len(list(it))
많은 요소 (예 : 수만 개 이상)를 생성하는 경우 목록에 넣는 것이 성능 문제가 될 수 있습니다. 그러나 대부분의 경우 성능이 중요하지 않은 아이디어의 간단한 표현입니다.
more_itertools
ilen
도구 를 구현하는 라이브러리입니다 .pip install more_itertools
import more_itertools as mit
mit.ilen(x for x in range(10))
# 10
나는 이것에 대한 카디널리티 패키지를 좋아한다 . 그것은 매우 가볍고 반복 가능한 것에 따라 가능한 가장 빠른 구현을 사용하려고한다.
용법:
>>> import cardinality
>>> cardinality.count([1, 2, 3])
3
>>> cardinality.count(i for i in range(500))
500
>>> def gen():
... yield 'hello'
... yield 'world'
>>> cardinality.count(gen())
2
이것들은 내 선택이 될 것입니다.
print(len([*gen]))
print(len(list(gen)))
'ProgramingTip' 카테고리의 다른 글
Laravel 5 클래스 'form'을 수 없습니다. (0) | 2020.12.06 |
---|---|
C #에서 이중 값 비교 (0) | 2020.12.06 |
iOS로 라이선스에서 이미지로드 (0) | 2020.12.06 |
쉘에서 마지막으로 캐치 작성 시도 (0) | 2020.12.06 |
SQL 서버에서 저장 프로 시저의 예약 된 실행 (0) | 2020.12.06 |