Reputation: 43
What is the most pythonic way to solve the following problem?
Given a list A, find all lists B, such that for i in range(len(A)): B[i] <= A[i]. Example of what I expect:
#Input
A = [1,2,0]
#Output
B = [[0,0,0],
[1,0,0],
[1,1,0],
[1,2,0],
[0,1,0],
[0,2,0]]
Thanks in advance!
Upvotes: 2
Views: 137
Reputation: 1377
This also works:
A = [1,2,0]
answers = [[] for element in A]
answers[0] = [[number,] for number in range(A[0]+1)]
for i in range(len(A)-1):
for possibility in answers[i]:
for valid_number in range(A[i+1]+1):
answers[i+1].append(possibility + [valid_number, ])
your_answer = answers[-1]
It could probably be written in a more compact way.
Upvotes: 0
Reputation: 6526
Here is a quite smart solution without using itertools
but using recursive function call. It works whatever the size of the input list:
A = [1,2,0]
def compute(A, B=[], n=0):
for i in range(A[n]+1):
A[n] = i
if A not in B: B.append(A[:])
if n+1 < len(A): compute(A, B, n+1) # recursive call here
return sorted(B)
B = compute(A)
print(B)
# [[0, 0, 0], [0, 1, 0], [0, 2, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0]]
Upvotes: 1
Reputation: 26315
I guess you could first generate all unique combinations of these numbers:
>>> import itertools
>>> A = [1,2,0]
>>> combs = set(itertools.combinations(itertools.chain(*(range(col+1) for col in A)), len(A)))
>>> combs
{(0, 1, 1), (0, 2, 0), (1, 1, 0), (1, 2, 0), (0, 0, 2), (0, 1, 2), (1, 0, 0), (0, 0, 1), (1, 0, 1), (1, 1, 2), (0, 0, 0), (0, 1, 0), (1, 0, 2)}
Then pick the ones that follow your condition:
>>> sorted(comb for comb in combs if all(comb[i] <= x for i, x in enumerate(A)))
[(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
But this is alot more inefficient than using itertools.product
, since it has to generate all the combinations beforehand, and sort at the end to retain order.
Upvotes: 0
Reputation: 12005
You can use itertools.product
to do this easily
>>> from itertools import product
>>> A
[1, 2, 0]
>>> B = list(product(*[list(range(e+1)) for e in A]))
>>> B
[(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0)]
>>>
If you want the o/p as list of list, convert the tuples to list
>>> B = [list(e) for e in B]
>>> B
[[0, 0, 0], [0, 1, 0], [0, 2, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0]]
>>>
If you dont wan't to use itertools.product
, you can have your custom implementation of product
>>> B = [[]];
>>> for t in [range(e+1) for e in A]:
... B = [x+[y] for x in B for y in t]
...
>>> B
[[0, 0, 0], [0, 1, 0], [0, 2, 0], [1, 0, 0], [1, 1, 0], [1, 2, 0]]
>>>
Upvotes: 7