Determine list of all possible products from a list of integers in Python

橙三吉。 提交于 2019-12-04 22:08:43

You can break this down into three steps:

  • get all the permutations of the list of numbers
  • for each of those permutations, create all the possible partitions
  • for each sublist in the partitions, calculate the product

For the permutations, you can use itertools.permutations, but as far as I know, there is no builtin function for partitions, but that's not too difficult to write (or to find):

def partitions(lst):
    if lst:
        for i in range(1, len(lst) + 1):
            for p in partitions(lst[i:]):
                yield [lst[:i]] + p
    else:
        yield []

For a list like (1,2,3,4), this will generate [(1),(2),(3),(4)], [(1),(2),(3,4)], [(1),(2,3),(4)], [(1),(2,3,4)], and so on, but not, e.g. [(1,3),(2),(4)]; that's why we also need the permutations. However, for all the permutations, this will create many partitions that are effectively duplicates, like [(1,2),(3,4)] and [(4,3),(1,2)] (182 for your data), but unless your lists are particularly long, this should not be too much of a problem.

We can combine the second and third step; this way we can weed out all the duplicates as soon as they arise:

data = (2, 2, 3, 4)
res = {tuple(sorted(reduce(operator.mul, lst) for lst in partition))
       for permutation in itertools.permutations(data)
       for partition in partitions(permutation)}

Afterwards, res is {(6, 8), (2, 4, 6), (2, 2, 3, 4), (2, 2, 12), (48,), (3, 4, 4), (4, 12), (3, 16), (2, 24), (2, 3, 8)}


Alternatively, you can combine it all in one, slightly more complex algorithm. This still generates some duplicates, due to the two 2 in your data set, that can again be removed by sorting and collecting in a set. The result is the same as above.

def all_partitions(lst):
    if lst:
        x = lst[0]
        for partition in all_partitions(lst[1:]):
            # x can either be a partition itself...
            yield [x] + partition
            # ... or part of any of the other partitions
            for i, _ in enumerate(partition):
                partition[i] *= x
                yield partition
                partition[i] //= x
    else:
        yield []

res = set(tuple(sorted(x)) for x in all_partitions(list(data)))

Your problem is basically one of find all subsets of a given set (multiset in your case). Once you have the subsets its straight forward to construct the output you've asked for.

For a set A find all the subsets [S0, S1, ..., Si]. For each subset Si, take (A - Si) | product(Si), where | is union and - is a set difference. You might not be interested in subsets of size 0 and 1, so you can just exclude those.

Finding subsets is a well known problem so I'm sure you can find resources on how to do that. Keep in mind that there are 2**N setbsets of a set with N elements.

Suppose you have a vector of 4 numbers (for instance (2,2,3,4)).

You can generate a grid (as that one showed below):

0 0 0 0
0 0 0 1
0 0 1 0 
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

Now remove the rows with all '0' and the rows with only one '1'.

0 0 1 1
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

Now you can substitute the '1' with the respective element in the vector. If your vector is (2,2,3,4) it becomes:

0 0 3 4
0 2 0 4
0 2 3 0
0 2 3 4
2 0 0 4
2 0 3 0
2 0 3 4
2 2 0 0
2 2 0 4
2 2 3 0
2 2 3 4

Try to implement this in Python. Below a pseudo code:

for i from 0 to 2^VECTOR_LEN:
    bin=convert_to_binary(i)
    if sum_binary_digit(bin) > 1:
       print(exec_moltiplication(bin,vector) 
       # if you want you can also use the bin vector as mask for the updating 
       # of your tuple of int with the result of the product and append it
       # in a list (as in your example).
       # For example if bin is (1 1 0 0) you can edit (2 2 3 4) in (4 3 4)
       # and append (4 3 4) inside the list or if it is (1 0 1 0) you can 
       # update (2 2 3 4) in (6 2 4)

WHERE:

  • vector: is the vector containing the numbers
  • VECTOR_LEN is the length of vector
  • convert_to_binary(num) is a function that convert an integer (num) to binary
  • sum_binary_digit(bin) is a function that sum the 1s in your binary number (bin)
  • exec_multiplication(vector,bin) take in input the vector (vector) and the binary (bin) and returns the value of the multiplication.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!