计算迭代器平均值的生成器

时间:2019-01-21 06:49:06

标签: python iterator generator

我有一个评估素数的迭代器。我想创建一个使用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

如果同时循环遍历rawprime_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})]

2 个答案:

答案 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]}