函数式python——为什么这些生成器中只有一个需要list()才能工作?

函数式python——为什么这些生成器中只有一个需要list()才能工作?,python,functional-programming,chinese-remainder-theorem,Python,Functional Programming,Chinese Remainder Theorem,从元组向量(剩余、模)计算中国剩余定理时,以下代码失败: c = ((1,5),(3,7),(11,13),(19,23)) def crt(c): residues, moduli = zip(*c) N = product(moduli) complements = (N/ni for ni in moduli) scaled_residues = (product(pair) for pair in zip(residues

从元组向量(剩余、模)计算中国剩余定理时,以下代码失败:

c = ((1,5),(3,7),(11,13),(19,23))

def crt(c):
        residues, moduli = zip(*c)
        N = product(moduli)
        complements = (N/ni for ni in moduli)
        scaled_residues = (product(pair) for pair in zip(residues,complements))
        inverses = (modular_inverse(*pair) for pair in zip(complements,moduli))
        si = (product(u) for u in zip(scaled_residues,inverses))
        result = sum(si) % N
        return result
将结果设为0(我猜生成的iterables是空的)。然而,以下代码工作得非常完美:

def crt(c):
        residues, moduli = zip(*c)
        N = product(moduli)
        complements = list((N/ni for ni in moduli)) # <-- listed
        scaled_residues = (product(pair) for pair in zip(residues,complements))
        inverses = (modular_inverse(*pair) for pair in zip(complements,moduli))
        si = (product(u) for u in zip(scaled_residues,inverses))
        result = sum(si) % N
        return result
def crt(c):
剩余物,模量=zip(*c)
N=乘积(模数)

complements=list((N/ni表示模中的ni))#您在
complements上迭代了两次。只能在生成器表达式上迭代一次


如果您使用的是Python2.x,
zip(剩余,补充)
将消耗
complements
,而
zip(补充,模块)
将一无所有。在Python3.x上,
zip
本身就是一个生成器,当
sum()
实际运行生成器时,问题会出现在代码的后面。每次迭代都会从
补遗中提取两个项目。

根据答案中的建议,我重新实现了问题中的代码,如下所示:

def complements(moduli,N):
        return (N/ni for ni in moduli)

def scaled_residues(residues,complements):
        return (product(pair) for pair in zip(residues,complements))

def inverses(complements,moduli):
        return (modular_inverse(*pair) for pair in zip(complements,moduli))

def crt_residue_terms(scaled_residues,inverses):
        return (product(u) for u in zip(scaled_residues,inverses))

 def crt(c):   
    residues, moduli = zip(*c)
    N = product(moduli)
    return sum(
            crt_residue_terms(
                    scaled_residues(residues,complements(moduli,N)),
                    inverses(complements(moduli,N),moduli)
            )) % N

现在,它不使用任何列表即可生成正确的8851结果。酷。

我喜欢你关于python的问题!这可能是同样的问题吗?也许你可以先打印
zip(剩余,补码)
,然后在迭代之前打印
zip(补码,模)
。@AlexL好的,我会试试。我认为最好写
[N/ni代表模中的ni]
而不是
列表((N/ni代表模中的ni))
Boom!就这样!我忘了发电机的事了。生成器的单次使用质量是否与其他函数式语言中的生成器相同…可能是Scala或Haskell?在后面的代码中,您的意思是什么?zip也是生成器?我猜这就是函数式编程被称为函数式编程的原因。如果我将上面的函数分解成更小的函数,而不是将生成器分配给变量,那么函数可以在需要时调用生成器,并且不会出现穷举。请注意,与流行的观点相反,生成器表达式并不总是比列表更有效。“如果你在小集合上迭代,通常内存的权衡是不值得的。”PauloScardine指出。我相信你。