Special kind of permutation - python

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

Related

A better way to do Cartesian Product [duplicate]

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

Dynamic Nested Loops Python

This is the array I require:
N = 6
A = [[x,y,z] for x in range(N+1) for y in range(N+1) for z in range(N+1) if x+y+z== N]
Is there any other way of doing this by only specifying the variable N and 3 instead of x,y,z?
I tried []*3 but can't get the required output.
You are looking for iterttols.product:
from itertools import product
N = 6
A = [(x,y,z) for x in range(N+1) for y in range(N+1) for z in range(N+1) if x+y+z== N]
B = [tup for tup in product(range(N+1), repeat=3) if sum(tup) == N]
print(A, B, A == B, sep='\n')
Gives:
[(0, 0, 6), (0, 1, 5), (0, 2, 4), (0, 3, 3), (0, 4, 2), (0, 5, 1), (0, 6, 0), (1, 0, 5), (1, 1, 4), (1, 2, 3), (1, 3, 2), (1, 4, 1), (1, 5, 0), (2, 0, 4), (2, 1, 3), (2, 2, 2), (2, 3, 1), (2, 4, 0), (3, 0, 3), (3, 1, 2), (3, 2, 1), (3, 3, 0), (4, 0, 2), (4, 1, 1), (4, 2, 0), (5, 0, 1), (5, 1, 0), (6, 0, 0)]
[(0, 0, 6), (0, 1, 5), (0, 2, 4), (0, 3, 3), (0, 4, 2), (0, 5, 1), (0, 6, 0), (1, 0, 5), (1, 1, 4), (1, 2, 3), (1, 3, 2), (1, 4, 1), (1, 5, 0), (2, 0, 4), (2, 1, 3), (2, 2, 2), (2, 3, 1), (2, 4, 0), (3, 0, 3), (3, 1, 2), (3, 2, 1), (3, 3, 0), (4, 0, 2), (4, 1, 1), (4, 2, 0), (5, 0, 1), (5, 1, 0), (6, 0, 0)]
True
Use itertools.combinations_with_replacement:
from itertools import combinations_with_replacement
n = 6
k = 3
# If you want a list of tuples:
lst = [item for item in list(combinations_with_replacement(range(n), k)) if sum(item) == n]
print(lst)
# [(0, 1, 5), (0, 2, 4), (0, 3, 3), (1, 1, 4), (1, 2, 3), (2, 2, 2)]
# If you want a list of lists:
lst = [list(item) for item in list(combinations_with_replacement(range(n), k)) if sum(item) == n]
print(lst)
# [[0, 1, 5], [0, 2, 4], [0, 3, 3], [1, 1, 4], [1, 2, 3], [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)

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