I am unsure how to define the problem I wish to solve, but from a combinations of numbers, e.g.:
(4, 3, 2)
I wish to make an iterator that goes over all 'nested' combinations of these numbers. What I mean by this is that it iterates over:
(0, 0, 0), (0, 1, 0), (0, 2, 0), (0, 3, 0), (0, 1, 1), (0, 1, 2), (0, 2, 1), (0, 2, 2), ...
(1, 0, 0), (1, 1, 0), (1, 2, 0), (1, 3, 0), (1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), ...
...
(4, 0, 0), (4, 1, 0), (4, 2, 0), (4, 3, 0), (4, 1, 1), (4, 1, 2), (4, 2, 1), (4, 2, 2), ...
Preferably it could also be constrained by a maximum sum capacity during the generation of combinations (i.e. sum(combination) < capacity).
I have created a recursive algorithm that generates these combinations, but it is very slow and hope there is a more efficient method.
import numpy as np
def combinations(current, c, c_set):
c_rec = c.copy()
if(current == 0):
while(c_rec[current] + 1 <= numbers[current] and c_rec[current] + 1 < capacity):
c_rec[current] += 1
c_set.append(c_rec.copy())
while(c_rec[current] + 1 <= numbers[current] and c_rec[current] + 1 < capacity):
c_rec[current] += 1
combinations(current - 1, c_rec, c_set)
c_set.append(c_rec)
numbers = (4,3,2)
n = len(numbers)
capacity = 7
c_init = np.zeros(n)
c_set = [c_init]
combinations(n - 1, c_init, c_set)
You can make use of itertools.product for this
from itertools import product
li = [4, 3, 2]
#Create a list of ranges
res = [range(item+1) for item in li]
#[range(0, 5), range(0, 4), range(0, 3)]
#Calculate cartesian product between elements of each list
prod = product(*res)
#Iterate over the elements
for item in prod:
print(item)
The output will be
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 1, 0)
(0, 1, 1)
...
(1, 0, 0)
(1, 0, 1)
(1, 0, 2)
(1, 1, 0)
(1, 1, 1)
...
(2, 0, 0)
(2, 0, 1)
(2, 0, 2)
(2, 1, 0)
(2, 1, 1)
.....
(3, 0, 0)
(3, 0, 1)
(3, 0, 2)
(3, 1, 0)
(3, 1, 1)
.....
I might not have fully understood your question, but wouldn't a simple nested for-loop structure solve your problem?
for x in range(4):
for y in range(3):
for z in range(2):
print((x, y, z))
You can use recursion with a generator:
start = (4, 3, 2)
def groups(d):
yield d
for i, [a, b] in enumerate(zip(d, start)):
if a < b:
yield from groups(tuple([*d[:i], d[i]+1, *d[i+1:]]))
result = set(groups((0, 0, 0)))
Output:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 3, 0), (0, 3, 1), (0, 3, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 3, 0), (1, 3, 1), (1, 3, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 3, 0), (2, 3, 1), (2, 3, 2), (3, 0, 0), (3, 0, 1), (3, 0, 2), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 2, 0), (3, 2, 1), (3, 2, 2), (3, 3, 0), (3, 3, 1), (3, 3, 2), (4, 0, 0), (4, 0, 1), (4, 0, 2), (4, 1, 0), (4, 1, 1), (4, 1, 2), (4, 2, 0), (4, 2, 1), (4, 2, 2), (4, 3, 0), (4, 3, 1), (4, 3, 2)]
Related
This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 8 months ago.
Do you know how to compute the cartesian product of n lists and n dimensions arrays?
example:
d = 3
x = [0, 1, 2]
y = [0, 1, 2]
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]
Please check if the below-mentioned solution works for you, do let me know if any changes are required:
import itertools
d = 3
x = [0, 1, 2]
y = [0, 1, 2]
third_lst = [0, 1, 2] # this list is required for the third dimension
input_lst = [x, y, third_lst]
final_lst = list(itertools.product(*input_lst))
print(final_lst)
Output:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]
I am working on some code to produce all possible permutations from a list. Such products are constrained exclusively to one specific size. My code works for regular permutations, but I do not know how to obtain permutations that follow this type of logic. I'm supposed to get all of the permutations that follow this sort of criss-cross pattern, where the first element is followed by another element and then repeated until the product reaches size z, into one big array.
For example, given an array like [0,1,2,3] and z=3,
One should return something like [[0,1,0][1,0,1][2,0,2][0,2,0][0,3,0][0,4,0]...]
Of course the output would change based on z, so, if we had z=4 the array would have subarrays that are of size 4, like [[0,1,0,1],[1,0,1,0],[2,0,2,0],[0,2,0,2], etc.]
Fundamentally, you just need to alternate two elements in the original array so they form that type of a-b/a-b-a/a-b-a-b/pattern, so two elements at a time are taken.
This is my code for basic permutations with size z.
def comb(k,array):
if k<=0:
return [[]]
else:
final=[]
for part in comb(k-1,array):
for e in array:
final.append([e]+part)
return final
I don't want to use any library because I am studying recursion specifically and that would be sort of pointless learning-wise. Thank you.
Use itertools.product:
from itertools import product
lst = [0,1,2,3]
result = list(product(lst,repeat=3))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (0, 3, 0), (0, 3, 1), (0, 3, 2), (0, 3, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 0), (1, 3, 1), (1, 3, 2), (1, 3, 3), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 0, 3), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 0), (2, 3, 1), (2, 3, 2), (2, 3, 3), (3, 0, 0), (3, 0, 1), (3, 0, 2), (3, 0, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 1, 3), (3, 2, 0), (3, 2, 1), (3, 2, 2), (3, 2, 3), (3, 3, 0), (3, 3, 1), (3, 3, 2), (3, 3, 3)]
Try permutations from itertools module:
l = [0, 1, 2, 3]
z = 3
out = list(permutations(l, r=z))
print(out)
# Output:
[(0, 1, 2),
(0, 1, 3),
(0, 2, 1),
(0, 2, 3),
(0, 3, 1),
(0, 3, 2),
(1, 0, 2),
(1, 0, 3),
(1, 2, 0),
(1, 2, 3),
(1, 3, 0),
(1, 3, 2),
(2, 0, 1),
(2, 0, 3),
(2, 1, 0),
(2, 1, 3),
(2, 3, 0),
(2, 3, 1),
(3, 0, 1),
(3, 0, 2),
(3, 1, 0),
(3, 1, 2),
(3, 2, 0),
(3, 2, 1)]
Check the code of permutations which is roughly equivalent.
For z=4:
l = [0, 1, 2, 3]
z = 4
out = list(permutations(l, r=z))
print(out)
# Output:
[(0, 1, 2, 3),
(0, 1, 3, 2),
(0, 2, 1, 3),
(0, 2, 3, 1),
(0, 3, 1, 2),
(0, 3, 2, 1),
(1, 0, 2, 3),
(1, 0, 3, 2),
(1, 2, 0, 3),
(1, 2, 3, 0),
(1, 3, 0, 2),
(1, 3, 2, 0),
(2, 0, 1, 3),
(2, 0, 3, 1),
(2, 1, 0, 3),
(2, 1, 3, 0),
(2, 3, 0, 1),
(2, 3, 1, 0),
(3, 0, 1, 2),
(3, 0, 2, 1),
(3, 1, 0, 2),
(3, 1, 2, 0),
(3, 2, 0, 1),
(3, 2, 1, 0)]
I just can't come up with a way to solve my problem: x is an integer. I want a list of all possibles combinations of x-tuples where those tuples' elements are in range from 0 to x (excluding x).
So if x = 3 I have 3^3 combinations: [(0,0,0),(0,0,1),(0,0,2),(0,1,0),(0,1,1),(0,1,2),(0,2,0),(0,2,1),(0,2,2),(1,0,0),(1,0,1),(1,0,2),(1,1,0),(1,1,1),(1,1,2),(1,2,0),(1,2,1),(1,2,2),(2,0,0),(2,0,1),(2,0,2),(2,1,0),(2,1,1),(2,1,2),(2,2,0),(2,2,1),(2,2,2)].
If x = 4 I would have 4^4 combinations with 4-tuples where the elements of those tuples are in {0,1,2,3}.
Here's the proper way to use itertools to get what you want:
list(itertools.product(range(3), repeat=3))
The output is:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1),
(0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (1, 0, 0),
(1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2),
(1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1),
(2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0),
(2, 2, 1), (2, 2, 2)]
Of course, this can scale up by using values other than 3. In general:
list(itertools.product(range(x), repeat=x))
will work for any x.
I think it's just a list comprehension:
mylist = [(x,y,z) for x in range(3) for y in range(3) for z in range(3)]
Note that using itertools.permutations(range(3)) doesn't generate duplicates, just the permutations of the set (0, 1, 2). I.e. you won't get (1, 1, 2), etc.
Ok, not permatations, but permutations with repeats perhaps.
Anyway, itertools.product() is doing that:
list(itertools.product([0,1,2],repeats=3))
result:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (0, 2, 1), (0, 2, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]
oh it's a dupe. But I found it too :-)
(Side remark: combinations are about subsets, and thus order of elements does not matter to them)
This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 7 years ago.
I'm new to Python and I wrote a function:
def f(x, y, z):
ret = []
for i in range(x):
for j in range(y):
for k in range(z):
ret.append((i, j, k))
return ret
print f(2, 3, 4)
Output:
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)]
But I'm not satisfied with that because I think there must be a shorter implementation.
So could any one give me some hint about that?
You can use itertools.product because that is essentially what you are after, the Cartesian product
>>> from itertools import product
>>> list(product(range(2), range(3), range(4)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)]
So replacing your existing function you could do
def f(x, y, z):
return list(product(range(x), range(y), range(z)))
To remove the number of times you have to type out range, you could accept a single list argument then use a generator expression such as
def f(l):
return list(product(*(range(i) for i in l)))
So then you could call it as
>>> f([2,3,4])
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)]
You can use list comprehension
>>> [(i, j, k) for i in range(2) for j in range(3) for k in range(4)]
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3)]
You you can write the function like:
def f(x, y, z):
return [(i, j, k) for i in range(x) for j in range(y) for k in range(z)]
I would like to create a list of numbers with three values and would like to cover every combination from 0 - 3. For example:
0, 0, 0
0, 0, 1
...
1, 0, 3
1, 1, 3
all the way to 3, 3, 3.
Is there a better way to do this than using multiple for loops?
Here is the code that I used:
for i in range (0, 4):
for x in range (0, 4):
for t in range (0, 4):
assign = [i, x, t]
Usually itertools.product:
list(itertools.product(range(4), repeat=3))
You can use the itertools.product() function for that:
from itertools import product
for i, x, t in product(range(4), repeat=3):
print (i, x, t)
Demo:
>>> from itertools import product
>>> for i, x, t in product(range(4), repeat=3):
... print (i, x, t)
...
(0, 0, 0)
(0, 0, 1)
(0, 0, 2)
(0, 0, 3)
(0, 1, 0)
# ... truncated for readability ...
(3, 2, 3)
(3, 3, 0)
(3, 3, 1)
(3, 3, 2)
(3, 3, 3)
You can use itertools.product:
>>> from itertools import product
>>> list(product({0, 1, 2, 3}, repeat=3))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (0, 3, 0), (0, 3, 1), (0, 3, 2), (0, 3, 3), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 0), (1, 3, 1), (1, 3, 2), (1, 3, 3), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 0, 3), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 0), (2, 3, 1), (2, 3, 2), (2, 3, 3), (3, 0, 0), (3, 0, 1), (3, 0, 2), (3, 0, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 1, 3), (3, 2, 0), (3, 2, 1), (3, 2, 2), (3, 2, 3), (3, 3, 0), (3, 3, 1), (3, 3, 2), (3, 3, 3)]
>>>
The itertools.product() is a great solution, but if you should happen to want a list of lists and not tuples, you could use this:
[ [x,y,z] for x,y,z in itertools.product(range(4), repeat=3)]
or the equivalent list comprehension:
[ [x,y,z] for x in range(0,4)
for y in range(0,4)
for z in range(0,4)]