Skip to content Skip to sidebar Skip to footer

How Do I Convert Python's Itertools.product Library From A List Comprehension To Normal For Loops?

According to http://docs.python.org/2/library/itertools.html#itertools.product the following function is equivalent to using their library (I removed a few things I don't need from

Solution 1:

You're very close: the right hand side of a nested list comprehension is written in the same order that you'd write the for loops, so you've got that right. However, in the listcomp version, first the RHS of the assignment is computed and then it's bound to the name on the LHS. So

result = [x+[y] for x in result for y in pool]

needs to become

new_result = []
for x in result:
    for y in pool:
        new_result.append(x+[y])
result = new_result

So that you're not modifying result as you iterate over it. If you wanted to forbid certain arrangements -- and you can write your constraint in such a way that it works for that iteration order, which fills in from left-to-right -- then you could do this:

def filtered_product(args, filter_fn):
    pools = map(tuple, args)
    result = [[]]for pool in pools:
        new_result = []
        for x in result:
            for y in pool:
                new_val = x+[y]
                if filter_fn(new_val):
                    new_result.append(x+[y])
        result = new_result
        print'intermediate result:', result
    for prod in result:
        yield tuple(prod)

which gives

In [25]: list(filtered_product([[1,2,3], [4,5,6], [7,8,9]], lambda x: sum(x) % 3 != 2))
intermediate result: [[1], [3]]
intermediate result: [[1, 5], [1, 6], [3, 4], [3, 6]]
intermediate result: [[1, 5, 7], [1, 5, 9], [1, 6, 8], [1, 6, 9], [3, 4, 8], [3, 4, 9], [3, 6, 7], [3, 6, 9]]
Out[25]: 
[(1, 5, 7),
 (1, 5, 9),
 (1, 6, 8),
 (1, 6, 9),
 (3, 4, 8),
 (3, 4, 9),
 (3, 6, 7),
 (3, 6, 9)]

Whether or not this gives you any benefit over simply using (p for p in itertools.product(whatever) if condition(p)) will depend upon how many branches you can prune, because as you can see it constructs all the intermediate lists in memory.

Solution 2:

The product function is generically multiplying the lists together in a form of reduction operation, which is probably unhelpful for you if you're trying to filter the results as you go. Instead you should write a product function that takes a fixed number of lists:

forxin list1:
    foryin list2:
        forzin list3:
            ifcondition(x, y, z):
                yieldtuple(x, y, z)

Solution 3:

Note that in the line result = [x+[y] for x in result for y in pool], result appears twice but it is not relevant. This expression builds a list using the old result, and then it assigns this new list into result.

That's probably what got you confused. An equivalent expanded version would be:

defproduct(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        tmp = []
        for x in result:   # note that it's the old 'result' herefor y in pool:
                tmp.append(x+[y])
        result = tmp
    for prod in result:
        yieldtuple(prod)

Post a Comment for "How Do I Convert Python's Itertools.product Library From A List Comprehension To Normal For Loops?"