A better way to do Cartesian Product [duplicate] - python

This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 1 year ago.
What I'm looking for is a way to do the cartesian product n amount of times, similar to:
[(i_1,...,i_n) for i_1 in range(x) ... for i_n in range(x)]
I am supposed to build my own function for this. I know I can do something along the lines of:
[...[7, 5, 6], [7, 5, 7], ...]
[...[7, 5, 6, 1], [7, 5, 7, 2], ...]
But, I'm looking for a more elegant solution. In fact, I would like to know if there is a way to do it like the first line of code above.

If you're allowed to use itertools then 1st solution below:
Try it online!
import itertools
print(list(itertools.product(range(2), range(3), range(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)]
Second solution without using any modules:
Try it online!
def f(*its):
if len(its) == 0:
yield ()
else:
for e in its[0]:
for tail in f(*its[1:]):
yield (e,) + tail
print(list(f(range(2), range(3), range(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)]

Related

compute the cartesian product of n lists and n dimensions arrays [duplicate]

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

Is there a way to efficiently iterate over 'nested' combinations in Python?

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

How to construct a list of tuples of all possible combinations

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)

Python: how to get this elegantly? [duplicate]

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

Create list of combinations

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

Categories