partitioned permutations in python - python

I wish to have a list of permutations on n elements [0,1,2,...], for n = n1 + n2 + n3. But such permutations are partitioned into m partitions.
For example for n1,n2 = 3,2 I would have:
0,1,2 | 3,4
0,1,2 | 4,3
0,2,1 | 3,4
0,2,1 | 4,3
...
2,1,0 | 4,3
if I use itertools:
product(permutations([0,1,2]),permutations([3,4]))
I get:
[((0, 1, 2), (3, 4)), ((0, 1, 2), (4, 3)), ((0, 2, 1), (3, 4)), ((0, 2, 1), (4, 3)), ((1, 0, 2), (3, 4)), ((1, 0, 2), (4, 3)), ((1, 2, 0), (3, 4)), ((1, 2, 0), (4, 3)), ((2, 0, 1), (3, 4)), ((2, 0, 1), (4, 3)), ((2, 1, 0), (3, 4)), ((2, 1, 0), (4, 3))]
But I would like:
[(0, 1, 2, 3, 4), (0, 1, 2, 4, 3), ...]
Also it would be great if the input could simply be the length of the partitions:
input = [3,2]
or
input = [4,3,2]
In the latter case I would get:
[(0,1,2,3, 4,5,6, 7,8),
(0,1,2,3, 4,5,6, 8,7),
(0,1,2,3, 4,6,5, 7,8),
...]
Any ideas?

As I understand the problem, the following code should work for your needs.
from itertools import permutations, product
def part_perm_iter(ns):
inds = [int(sum(ns[:i])) for i in xrange(len(ns)+1)]
pair_inds = zip(inds,inds[1:])
for p in product( *[permutations(xrange(a,b)) for a, b in pair_inds ] ):
yield sum(p,())
For example, print list(part_perm_iter([2,2])) will print:
[(0, 1, 2, 3), (0, 1, 3, 2), (1, 0, 2, 3), (1, 0, 3, 2)]

Related

Special kind of permutation

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

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

How to randomly pick k items from a list of n size in python

I want to know how to randomly pick k items from a list of n size for ALL possible combinations.
For example, let A = [1, 2, 3, 4] and K = 3. Then it should return [1, 2, 3], [1, 2, 4], [1, 3, 4], and [2, 3, 4].
You are looking for itertools.combinations. For example:
>>> my_list = A = [1, 2, 3, 4]
>>> k = 3
>>> from itertools import combinations
>>> list(combinations(my_list, k))
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
If the ordering inside the results matters you might use itertools.permutations to get all permutations as well - putting them into a set removes duplicates stemming from duplicate numbers in your list
import itertools
n = 3
my_list = [1, 2, 3, 2 ,1]
print( set(itertools.permutations(my_list, n))) # or list, see below
Output:
{(1, 2, 1), (3, 1, 2), (2, 3, 2), (1, 3, 2), (3, 1, 1), (3, 2, 1), (1, 2, 2),
(1, 1, 3), (2, 2, 1), (2, 1, 1), (1, 3, 1), (2, 3, 1), (1, 2, 3), (1, 1, 2), ...}
# with set: 17 items
[(1, 2, 3), (1, 2, 2), (1, 2, 1), (1, 3, 2), (1, 3, 2), (1, 3, 1), (1, 2, 2),
(1, 2, 3), (1, 2, 1), (1, 1, 2), (1, 1, 3), (1, 1, 2), (2, 1, 3), (2, 1, 2), ...]
# with list: 60 items
Difference between permutations and combinations:
# permutations - based on all values on any position in the resulttuple
[(1, 2, 3), (1, 2, 2), (1, 2, 1), (1, 3, 2), (1, 3, 2), (1, 3, 1), (1, 2, 2), (1
, 2, 3), (1, 2, 1), (1, 1, 2), (1, 1, 3), (1, 1, 2), (2, 1, 3), (2, 1, 2), (2, 1
, 1), (2, 3, 1), (2, 3, 2), (2, 3, 1), (2, 2, 1), (2, 2, 3), (2, 2, 1), (2, 1, 1
), (2, 1, 3), (2, 1, 2), (3, 1, 2), (3, 1, 2), (3, 1, 1), (3, 2, 1), (3, 2, 2),
(3, 2, 1), (3, 2, 1), (3, 2, 2), (3, 2, 1), (3, 1, 1), (3, 1, 2), (3, 1, 2), (2,
1, 2), (2, 1, 3), (2, 1, 1), (2, 2, 1), (2, 2, 3), (2, 2, 1), (2, 3, 1), (2, 3,
2), (2, 3, 1), (2, 1, 1), (2, 1, 2), (2, 1, 3), (1, 1, 2), (1, 1, 3), (1, 1, 2)
, (1, 2, 1), (1, 2, 3), (1, 2, 2), (1, 3, 1), (1, 3, 2), (1, 3, 2), (1, 2, 1), (
1, 2, 2), (1, 2, 3)]
# combinations - based on position in source list not on value order in tuple preserved
[(1, 2, 3), (1, 2, 2), (1, 2, 1), (1, 3, 2), (1, 3, 1), (1, 2, 1), (2, 3, 2), (2
, 3, 1), (2, 2, 1), (3, 2, 1)]
Press any key to continue . . .

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

Is there a cleaner way than using for loops

I would like to know if there are any other ways to loop and manipulate data located in separate arrays.
import numpy as np
a = np.arange(2)
b = np.arange(5)
c = np.arange(5)
l1 = []
for x in a:
l2 = []
for y in b:
l3 = []
y = x + 1
for z in c:
z = x + y
t = (x,y,z)
l3.append(t)
l2.append(l3)
l1.append(l2)
print l1
This code does exactly what you are doing.
def method(lst, range1, range2):
for i in lst:
yield [[(i, i+1, 1+(i*2))]*range2]*range1
Can even be turned into a generator expression:
def gen_method(lst, r1, r2):
return ([[(i, i+1, 1+(i*2))]*r2]*r1 for i in lst)
Test it yourself if you like.
My tests:
a = range(2)
b = range(5)
c = range(5)
def your_method(a, b, c):
l1 = []
for x in a:
l2 = []
for y in b:
l3 = []
y = x + 1
for z in c:
z = x + y
t = (x,y,z)
l3.append(t)
l2.append(l3)
l1.append(l2)
return l1
def my_method(lst, range1, range2):
for i in lst:
yield [[(i, i+1, 1+(i*2))]*range2]*range1
yours = your_method(a, b, c)
mine = list(my_method(a, len(b), len(c)))
print yours
print '==='
print mine
print '==='
print yours == mine
>>>
[[[(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)]], [[(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]]]
===
[[[(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)], [(0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1), (0, 1, 1)]], [[(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)], [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]]]
===
True
Well, you can compress the code using list comprehensions:
[[[(x,x+1,x*2 +1)]*len(c)]*len(b) for x in a]
What this does is loop for all x in a, and create a list of elements, where each element is a list generated for all y in b, where each element of that list is (x,x+1,2*x+1) for all z in c.
An alternative approach is to use itertools, convert the resulting list to numpy array and reshape it
import numpy as np
import itertools as it
a = np.arange(2)
b = np.arange(5)
c = np.arange(5)
l1 = np.array([(i, i+1, i*2+1) for i, rb, rb in it.product(a, b, c)])
l1 = l1.reshape(len(a), len(b), len(c), len(d[0]))
It might be that this gets more memory consuming than all the other approaches as the size increases, but it's only two lines and creates unique elements for each triplet instead of just creating multiple pointers to the same object.
Edit
An other way, that also allows to keep the triplet (i, i+1, i*1+1) as a list is:
l1 = np.empty([len(a), len(b), len(c)], dtype=object)
for i, rb, rb in it.product(a, b, c):
l1[i,ra, rb] = (i, i+1, i*2+1)

Categories