简体   繁体   中英

Manual product with unknown number of arguments

The following examples give the same result:

A.

product = []
for a in "abcd":
    for b in "xy":
        product.append((a,b))

B.

from itertools import product
list(product("abcd","xy"))

How can I calculate the cartesian product like in example A when I don't know the number of arguments n?

REASON I'm asking this:

Consider this piece of code:

allocations = list(product(*strategies.values()))
for alloc in allocations:
    PWC[alloc] = [a for (a,b) in zip(help,alloc) if coalitions[a] >= sum(b)]

The values of the strategies dictionary are list of tuples, help is an auxiliary variable (a list with the same length of every alloc ) and coalitions is another dictionary that assigns to the tuples in help some numeric value.

Since strategies values are sorted, I know that the if statement won't be true anymore after a certain alloc . Since allocations is a pretty big list, I would avoid tons of comparisons and tons of sums if I could use the example algorithm A.

You can do:

items = ["abcd","xy"]

from itertools import product
list(product(*items))

The list items can contain an arbitrary number of strings and it'll the calculation with product will provide you with the Cartesian product of those strings.

Note that you don't have to turn it into a list - you can iterate over it and stop when you no longer wish to continue:

for item in product(*items):
    print(item)
    if condition:
        break

If you just want to abort the allocations after you hit a certain condition, and you want to avoid generating all the elements from the cartesian product for those, then simply don't make a list of all combinations in the first place.

itertools.product is lazy that means that it will only generate a single value of the cartesian product at a time. So you never need to generate all elements, and you also never need to compare the elements then. Just don't call list() on the result as that would iterate the whole sequence and store all possible combinations in memory:

allocations = product(*strategies.values())
for alloc in allocations:
    PWC[alloc] = [a for (a,b) in zip(help,alloc) if coalitions[a] >= sum(b)]

    # check whether you can stop looking at more values from the cartesian product
    if someCondition(alloc):
        break

It's just important to note how itertools.product generates the values, what pattern it follows. It's basically equivalent to the following:

for a in firstIterable:
    for b in secondIterable:
        for c in thirdIterable:
            …
                for n in nthIterable:
                    yield (a, b, c, …, n)

So you get an increasing pattern from the left side of your iterables. So make sure that you order the iterables in a way that you can correctly specify a break condition.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM