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

情到浓时终转凉″ 提交于 2020-01-13 07:30:10

问题


In Python 2.7 I need a method that returns all possible products of a list or tuple of int. Ie. if input is (2, 2, 3, 4), then I'd want a output like

  • (3, 4, 4), 2 * 2 = 4
  • (2, 4, 6), 2 * 3 = 6
  • (2, 3, 8), 2 * 4 = 8
  • (3, 4, 4), 2 * 2 = 4
  • (2, 2, 12), 3 * 4 = 12
  • (2, 24), 2 * 3 * 4 = 24
  • (3, 16), 2 * 2 * 4 = 16
  • (4, 12), 2 * 2 * 3 = 12
  • (48), 2 * 2 * 3 * 4 = 48

wrapped up in a list or tuple. I figure that a nice implementation is probably possible using combinations from itertools, but I'd appreciate any help. Note that I am only interested in distinct lists, where order of int plays no role.

EDIT

Some futher explanation for some clarification. Take the first output list. Input is (2, 2, 3, 4) (always). Then I take 2 and 2 out of the list and multiply them, so now I am left with a list (3, 4, 4). 3 and 4 from the input and the last 4 from the product.

I haven't tried anything yet since I just can't spin my head around that kind of loop. But I can't stop thinking about the problem, so I'll add some code if I do get a suggestion.


回答1:


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)))



回答2:


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.




回答3:


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.


来源:https://stackoverflow.com/questions/39428179/determine-list-of-all-possible-products-from-a-list-of-integers-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!