我有一个评估素数的迭代器。我想创建一个使用prime-iterator作为输入参数的生成器,该生成器评估循环质数的平均值:
from itertools import islice, tee
def only_primes(stream):
try:
while True:
is_valid, value = next(stream)
while not is_valid:
is_valid, value = next(stream)
yield value
except StopIteration:
return
def is_prime(n):
if n < 2:
return False, n
elif n == 2:
return True, n
sqrt_n = int(n**0.5)+1
return len([i for i in range(2, sqrt_n+1) if n % i == 0]) == 0, n
prime_iterator = only_primes(map(is_prime, range(100)))
def prime_av(stream):
"""Generator that yields average value of looped prime numbers"""
n = 0
stats = dict()
stats['mean'] = 0
try:
while True:
prime = next(stream)
n += 1
stats['mean'] *= n - 1
stats['mean'] += prime
stats['mean'] /= n
yield stats
except StopIteration:
return
如果同时循环遍历raw
和prime_av(stats)
迭代器,则仅输出最后一个平均值。为什么?
raw, stats = tee(prime_iterator)
list(islice(zip(raw, prime_av(stats)), 10))
输出:
[(2, {'mean': 12.9}),
(3, {'mean': 12.9}),
(5, {'mean': 12.9}),
(7, {'mean': 12.9}),
(11, {'mean': 12.9}),
(13, {'mean': 12.9}),
(17, {'mean': 12.9}),
(19, {'mean': 12.9}),
(23, {'mean': 12.9}),
(29, {'mean': 12.9})]
答案 0 :(得分:1)
问题在于平均迭代器不断更改同一个字典对象并产生它。 如果在循环期间打印结果,则结果是您期望的结果,但是如果将结果放入列表中(如您所做的那样),那么最后该列表将仅包含对相同对象的引用,当然还具有最后计算的平均值作为值。
将代码更改为:
def prime_av(stream):
"""Generator that yields average value of looped prime numbers"""
n = 0
S = 0
try:
while True:
prime = next(stream)
n += 1
S *= n - 1
S += prime
S /= n
yield {"mean": S}
except StopIteration:
return
会像您期望的那样工作,因为在每次迭代中都会分配一个新的新字典。
答案 1 :(得分:0)
问题出在这里:
stats['mean'] = 0
在这里:
yield stats
您看到重复打印的相同值,因为您正在重复生成对同一词典的引用。这些引用均保存在列表中。然后,您打印列表。如果您想在每次更新时查看此字典的中间状态,请在每次更改时打印该字典,而不要进行所有更新并打印。这就像更改它一样简单:
print(list(islice(zip(raw, prime_av(stats)), 10)))
像这样:
for i in islice(zip(raw, prime_av(stats)), 10):
print(*i)
如果想要这些方法的列表,则需要将它们添加到列表中,而不是通过更改此方法来重复更新单个值:
def prime_av(stream):
"""Generator that yields average value of looped prime numbers"""
n = 0
stats = dict()
stats['mean'] = 0
try:
while True:
prime = next(stream)
n += 1
stats['mean'] *= n - 1
stats['mean'] += prime
stats['mean'] /= n
yield stats
except StopIteration:
return
对此:
def prime_av(stream):
"""Generator that yields average value of looped prime numbers"""
n = 0
stats = dict()
stats['mean'] = [0]
try:
while True:
prime = next(stream)
n += 1
stats['mean'].append(stats['mean'][-1])
stats['mean'][-1] *= n - 1
stats['mean'][-1] += prime
stats['mean'][-1] /= n
yield stats
except StopIteration:
return
然后,当您执行此操作时:
x = list(islice(zip(raw, prime_av(stats)), 10))
值的字典在x[1][1]
中:
{'mean': [0, 2.0, 2.5, 3.3333333333333335, 4.25, 5.6, 6.833333333333333, 8.285714285714286, 9.625, 11.11111111111111, 12.9]}