Functional python -- why does only one of these generators require list() to work?
chinese-remainder-theorem, functional-programming, python
Solution
You iterate twice over `complements`. You can only iterate once over a generator expression.
If you are on Python 2.x, `zip(residues,complements)` will consume `complements` and there is nothing left for `zip(complements,moduli)`. On Python 3.x `zip` is a generator itself and the problem appears later in the code, when `sum()` actually runs the generators. It would pull two items from `complements` for each iteration.
Problem
In computing the Chinese Remainder theorem from a vector of tuples (residue, modulus) the following code fails : ``` 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 ``` Giving the result as 0 ( I guess the generated iterables are empty ). Yet the following code works perfectly : ``` 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 ``` Which yields (a) correct result of 8851. Why should I have to `list(` one of the first generators? Adding `list` to any subsequent generator does not change the fail (0) result. Only listing this first generator produces the correct result. What is going on here ?