제너레이터 출력 길이
Python은 열심인 사람의 길이를 얻는 좋은 방법을 제공합니다.len(x)
그것은.하지만 발전기 이해와 함수로 대표되는 게으른 반복 가능성에 대해서는 비슷한 것을 찾을 수 없었습니다.물론 다음과 같은 것을 쓰는 것은 어렵지 않습니다.
def iterlen(x):
n = 0
try:
while True:
next(x)
n += 1
except StopIteration: pass
return n
하지만 자전거를 다시 구현하고 있다는 느낌을 지울 수가 없습니다.
(제가 함수를 타이핑하는 동안, 한 생각이 떠올랐습니다. 아마도 그것은 그것의 주장을 "파괴"하기 때문에, 그러한 함수는 정말로 없을지도 모릅니다.하지만 제 경우에는 문제가 되지 않습니다.)
추신: 첫 번째 답변과 관련하여 - 네, 비슷한 것입니다.len(list(x))
그것도 효과가 있겠지만, 그것은 메모리의 사용을 급격하게 증가시킵니다.
추신: 다시 확인했습니다...추신을 무시하세요, 제가 시도하다가 실수를 한 것 같습니다, 작동이 잘 됩니다.폐를 끼쳐서 죄송합니다.
가장 쉬운 방법은 아마도 그냥sum(1 for _ in gen)
여기서 gen은 발전기입니다.
그 토론의 요약을 알고 싶은 사람들을 위해.다음을 사용하여 5천만 길이의 제너레이터 식을 계산한 최종 최고 점수:
len(list(gen))
,len([_ for _ in gen])
,sum(1 for _ in gen),
ilen(gen)
(추가_iter 도구에서),reduce(lambda c, i: c + 1, gen, 0)
,
실행 성능(메모리 소비 포함)에 따라 정렬되어 있으면 다음과 같이 놀라게 됩니다.
#1: test_list.py:8: 0.492 KiB
gen = (i for i in data*1000); t0 = monotonic(); len(list(gen))
('list, sec', 1.9684218849870376)
#2: test_list_compr.py:8: 0.867 KiB
gen = (i for i in data*1000); t0 = monotonic(); len([i for i in gen])
('list_compr, sec', 2.5885991149989422)
#3: test_sum.py:8: 0.859 KiB
gen = (i for i in data*1000); t0 = monotonic(); sum(1 for i in gen); t1 = monotonic()
('sum, sec', 3.441088170016883)
#4: more_itertools/more.py:413: 1.266 KiB
d = deque(enumerate(iterable, 1), maxlen=1)
test_ilen.py:10: 0.875 KiB
gen = (i for i in data*1000); t0 = monotonic(); ilen(gen)
('ilen, sec', 9.812256851990242)
#5: test_reduce.py:8: 0.859 KiB
gen = (i for i in data*1000); t0 = monotonic(); reduce(lambda counter, i: counter + 1, gen, 0)
('reduce, sec', 13.436614598002052)
그렇게,len(list(gen))
가장 빈도가 높고 메모리 소모가 적음
일반적인 경우에는 할 수 없기 때문에 없습니다. 게으른 무한 발생기가 있으면 어떻게 합니까?예:
def fib():
a, b = 0, 1
while True:
a, b = b, a + b
yield a
이것은 결코 끝나지 않지만 피보나치 숫자를 생성합니다.당신은 전화로 원하는 만큼의 피보나치 번호를 얻을 수 있습니다.next()
.
항목 수를 알아야 할 경우에는 항목을 한 번만 선형으로 반복할 수 없으므로 일반 목록과 같은 다른 데이터 구조를 사용하십시오.
def count(iter):
return sum(1 for _ in iter)
아니면 더 나은 것:
def count(iter):
try:
return len(iter)
except TypeError:
return sum(1 for _ in iter)
눈에 띄는 것이라면, 그것은 그것을 던질 것입니다.TypeError
.
또는 생성기에서 특정 항목을 카운트하려는 경우:
def count(iter, key=None):
if key:
if callable(key):
return sum(bool(key(x)) for x in iter)
return sum(x == key for x in iter)
try:
return len(iter)
except TypeError:
return sum(1 for _ in iter)
enumerate()를 사용하여 생성된 데이터 스트림을 순환한 다음 마지막 숫자(항목 수)를 반환할 수 있습니다.
itertools.izip()과 함께 itertools.count()를 사용하려고 했지만 실패했습니다.이것이 제가 생각한 가장 좋은/짧은 답변입니다.
#!/usr/bin/python
import itertools
def func():
for i in 'yummy beer':
yield i
def icount(ifunc):
size = -1 # for the case of an empty iterator
for size, _ in enumerate(ifunc()):
pass
return size + 1
print list(func())
print 'icount', icount(func)
# ['y', 'u', 'm', 'm', 'y', ' ', 'b', 'e', 'e', 'r']
# icount 10
Kamil Kisiel의 솔루션이 훨씬 더 좋습니다.
def count_iterable(i):
return sum(1 for e in i)
정의에 따르면, 생성기의 하위 집합만 특정 수의 인수(사전 정의된 길이) 후에 반환되고, 심지어는 이러한 유한 생성기의 하위 집합만 예측 가능한 끝을 갖습니다(생성기에 액세스하면 더 일찍 생성기를 중지할 수 있는 부작용이 발생할 수 있습니다).
제너레이터에 길이 방법을 구현하려면 먼저 "길이"(전체 요소 수)를 정의해야 합니다.남은 요소의 수?)를 선택한 다음 생성기를 클래스로 래핑합니다.다음은 예입니다.
class MyFib(object):
"""
A class iterator that iterates through values of the
Fibonacci sequence, until, optionally, a maximum length is reached.
"""
def __init__(self, length):
self._length = length
self._i = 0
def __iter__(self):
a, b = 0, 1
while not self._length or self._i < self._length:
a, b = b, a + b
self._i += 1
yield a
def __len__(self):
"This method returns the total number of elements"
if self._length:
return self._length
else:
raise NotImplementedError("Infinite sequence has no length")
# or simply return None / 0 depending
# on implementation
사용 방법은 다음과 같습니다.
In [151]: mf = MyFib(20)
In [152]: len(mf)
Out[152]: 20
In [153]: l = [n for n in mf]
In [154]: len(l)
Out[154]: 20
In [155]: l
Out[155]:
[1,
1,
2,
...
6765]
In [156]: mf0 = MyFib(0)
In [157]: len(mf0)
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-157-2e89b32ad3e4> in <module>()
----> 1 len(mf0)
/tmp/ipython_edit_TWcV1I.py in __len__(self)
22 return self._length
23 else:
---> 24 raise NotImplementedError
25 # or simply return None / 0 depending
26 # on implementation
NotImplementedError:
In [158]: g = iter(mf0)
In [159]: l0 = [g.next(), g.next(), g.next()]
In [160]: l0
Out[160]: [1, 1, 2]
메모리 효율적이고 순수하게 기능적인 솔루션을 사용하려면 reduce(함수,iterable[,initializer])를 사용합니다.
>>> iter = "This string has 30 characters."
>>> reduce(lambda acc, e: acc + 1, iter, 0)
30
패키지를 사용하여 간단한 해결 방법을 시도해 보십시오.예:
>>> import more_itertools
>>> it = iter("abcde") # sample generator
>>> it
<str_iterator at 0x4ab3630>
>>> more_itertools.ilen(it)
5
이건 해킹이야, 하지만 네가 정말 원한다면,len
은 일반적인할 수 수 .len
.
그len
함수는 기본적으로 다음과 같습니다(단, 구현은 일반적으로 추가 검색을 방지하기 위한 몇 가지 최적화를 제공합니다).
def len(iterable):
return iterable.__len__()
는 우리의 따서우우의를 할 수 .new_len
그것을 시도하기 위해, 그리고 만약.__len__
존재하지 않습니다. 반복 가능한 값을 사용하여 요소의 수를 계산합니다.
def new_len(iterable):
try:
return iterable.__len__()
except AttributeError:
return sum(1 for _ in iterable)
Python 2/3에서 위의 작업은 (제가 알기로는) 상상할 수 있는 모든 종류의 실행 가능한 작업을 포함해야 합니다.
언급URL : https://stackoverflow.com/questions/393053/length-of-generator-output
'programing' 카테고리의 다른 글
matplotlib에서 두 수직선 사이에 채우기 (0) | 2023.07.19 |
---|---|
vuejs 입력 양식 바인딩(v-for 루프 데이터) (0) | 2023.07.19 |
파이썬 .pyi 확장자에서 "i"는 무엇을 나타냅니까? (0) | 2023.07.09 |
SQL Server(C# 클라이언트)에서 많은 데이터를 대량으로 삽입하는 가장 빠른 방법은 무엇입니까? (0) | 2023.07.09 |
푸시 인증서 갱신 및 현재 앱 스토어 앱 작동 유지 (0) | 2023.07.09 |