Splitting a list into all combinations - python

I am aware of many posts with the similar questions and have been through many of them. However, I am not able to do what I need.
I have list L=[0,1,2,3,4,5] which I want to split into a pair of tuples. For example:
[(0,1,2),(3,4,5)]
[(0,1,3),(2,4,5)]
[(0,1,4),(2,4,5)]
...
Each tuple needs to contain half of the elements from the original list (in this example 3 of 6). A solution needs to produce every combination of tuples using 3 elements.
I can easily find all the possible tuple within the list using
list(itertools.combinations(L, 3))
[(0, 1, 2),
(0, 1, 3),
(0, 1, 4),
(0, 1, 5),
(0, 2, 3),
(0, 2, 4),
...]
Does itertools offers any workround for this as well?

There may be more performant solutions that avoid a complete extra iteration of the list for the other half, but that should be rather negligible:
l = [[x, tuple(y for y in L if y not in x)] for x in combinations(L, 3)]
[[(0, 1, 2), (3, 4, 5)],
[(0, 1, 3), (2, 4, 5)],
[(0, 1, 4), (2, 3, 5)],
[(0, 1, 5), (2, 3, 4)],
[(0, 2, 3), (1, 4, 5)],
[(0, 2, 4), (1, 3, 5)],
[(0, 2, 5), (1, 3, 4)],
[(0, 3, 4), (1, 2, 5)],
[(0, 3, 5), (1, 2, 4)],
[(0, 4, 5), (1, 2, 3)],
[(1, 2, 3), (0, 4, 5)],
[(1, 2, 4), (0, 3, 5)],
[(1, 2, 5), (0, 3, 4)],
[(1, 3, 4), (0, 2, 5)],
[(1, 3, 5), (0, 2, 4)],
[(1, 4, 5), (0, 2, 3)],
[(2, 3, 4), (0, 1, 5)],
[(2, 3, 5), (0, 1, 4)],
[(2, 4, 5), (0, 1, 3)],
[(3, 4, 5), (0, 1, 2)]]
This depends on the absence of duplicates in the original list. Otherwise you'd have to work with the indexes instead. The following modification uses the same approach, but uses the list indexes for the combinations and can thus handle duplicates in the original list:
indexes = ((x, (y for y in L if y not in x)) for x in combinations(range(len(L)), 3))
l = [[tuple(L[a] for a in A), tuple(L[b] for b in B)] for A, B in indexes]

Related

Iterating 2 permutation sets

Let's say I start with these two hypothetical lists: color and shape.
I have 15 colors and let's say a recursively infinite number of shapes (like number of sides of a regular ngon). At its most basic it starts like
color_list, shape_list = [1], [1]
up to the complexity I mentioned, one example of length 3 might be
color_list, shape_list = [15,9,7], [1,3,7]
These numbers are arbitrary to compare one particular permutation that combines color 15 with shape 1, color 9 with shape 3, color 7 with shape 7.
How would I create an iteration over every possible permutation that returns something from the [1], [1] up to say [15,15,15,15,15], [n,n,n,n,n]?
IIUC, you are trying to do the following -
Create color, shape combinations with some lower and upper limit for each (color = 3, shape = 5), (color = 1, shape = 99) etc.
Then you are trying to permute over these color combinations for each permutation order from 1 to m (in your example m = 5)
Here is a piece of code that should get you something similar. Please do note, this will explode exponentially, so avoid larger limits.
import itertools
color_i = 1
color_n = 5
shape_i = 1
shape_n = 6
permutes = 3
# color, shape combos
combos = list(itertools.product(range(color_i, color_n+1), range(shape_i, shape_n+1)))
# create permutations from the color, shape combos
permutations = []
for p in range(permutes):
for i in itertools.permutations(combos,r=p+1):
permutations.append(list(zip(*i)))
permutations
[[(1,), (1,)],
[(1,), (2,)],
[(1,), (3,)],
[(1,), (4,)],
[(1,), (5,)],
[(1,), (6,)],
[(2,), (1,)],
[(2,), (2,)],
[(2,), (3,)],
[(2,), (4,)],
[(2,), (5,)],
[(2,), (6,)],
[(3,), (1,)],
[(3,), (2,)],
[(3,), (3,)],
[(3,), (4,)],
[(3,), (5,)],
[(3,), (6,)],
[(4,), (1,)],
[(4,), (2,)],
[(4,), (3,)],
[(4,), (4,)],
[(4,), (5,)],
[(4,), (6,)],
[(5,), (1,)],
[(5,), (2,)],
[(5,), (3,)],
[(5,), (4,)],
[(5,), (5,)],
[(5,), (6,)],
[(1, 1), (1, 2)],
[(1, 1), (1, 3)],
...,
[(1, 4), (1, 2)],
[(1, 4), (1, 3)],
[(1, 4), (1, 4)],
[(1, 4), (1, 5)],
[(1, 4), (1, 6)],
[(1, 5), (1, 1)],
[(1, 5), (1, 2)],
[(1, 5), (1, 3)],
[(1, 5), (1, 4)],
[(1, 5), (1, 5)],
[(1, 5), (1, 6)],
[(1, 1), (2, 1)],
[(1, 1), (2, 3)],
[(1, 1), (2, 4)],
[(1, 1), (2, 5)],
[(1, 1), (2, 6)],
[(1, 2), (2, 1)],
[(1, 2), (2, 2)],
...,
[(4, 4), (3, 6)],
[(4, 5), (3, 1)],
[(4, 5), (3, 2)],
[(4, 5), (3, 3)],
[(4, 5), (3, 4)],
[(4, 5), (3, 5)],
[(4, 5), (3, 6)],
[(4, 1), (4, 1)],
[(4, 1), (4, 2)],
[(4, 1), (4, 3)],
[(4, 1), (4, 4)],
[(4, 1), (4, 5)],
...,
[(5, 5), (6, 2)],
[(5, 5), (6, 3)],
[(5, 5), (6, 4)],
[(5, 5), (6, 5)],
[(1, 1, 1), (1, 2, 3)],
[(1, 1, 1), (1, 2, 4)],
[(1, 1, 1), (1, 2, 5)],
[(1, 1, 1), (1, 2, 6)],
[(1, 1, 2), (1, 2, 1)],
[(1, 1, 2), (1, 2, 2)],
[(1, 1, 2), (1, 2, 3)],
...,
[(1, 1, 4), (1, 2, 6)],
[(1, 1, 5), (1, 2, 1)],
[(1, 1, 5), (1, 2, 2)],
[(1, 1, 5), (1, 2, 3)],
[(1, 1, 5), (1, 2, 4)],
[(1, 1, 5), (1, 2, 5)],
[(1, 1, 5), (1, 2, 6)],
[(1, 1, 1), (1, 3, 2)],
[(1, 1, 1), (1, 3, 4)],
[(1, 1, 1), (1, 3, 5)],
[(1, 1, 1), (1, 3, 6)],
[(1, 1, 2), (1, 3, 1)],
[(1, 1, 2), (1, 3, 2)],
[(1, 1, 2), (1, 3, 3)],
[(1, 1, 2), (1, 3, 4)],
[(1, 1, 2), (1, 3, 5)],
[(1, 1, 2), (1, 3, 6)],
[(1, 1, 3), (1, 3, 1)],
[(1, 1, 3), (1, 3, 2)],
[(1, 1, 3), (1, 3, 3)],
[(1, 1, 3), (1, 3, 4)],
[(1, 1, 3), (1, 3, 5)],
[(1, 1, 3), (1, 3, 6)],
[(1, 1, 4), (1, 3, 1)],
[(1, 1, 4), (1, 3, 2)],
[(1, 1, 4), (1, 3, 3)],
[(1, 1, 4), (1, 3, 4)],
[(1, 1, 4), (1, 3, 5)],
[(1, 1, 4), (1, 3, 6)],
[(1, 1, 5), (1, 3, 1)],
[(1, 1, 5), (1, 3, 2)],
[(1, 1, 5), (1, 3, 3)],
[(1, 1, 5), (1, 3, 4)],
[(1, 1, 5), (1, 3, 5)],
[(1, 1, 5), (1, 3, 6)],
[(1, 1, 1), (1, 4, 2)],
[(1, 1, 1), (1, 4, 3)],
[(1, 1, 1), (1, 4, 5)],
[(1, 1, 1), (1, 4, 6)],
[(1, 1, 2), (1, 4, 1)],
[(1, 1, 2), (1, 4, 2)],
[(1, 1, 2), (1, 4, 3)],
[(1, 1, 2), (1, 4, 4)],
[(1, 1, 2), (1, 4, 5)],
[(1, 1, 2), (1, 4, 6)],
[(1, 1, 3), (1, 4, 1)],
[(1, 1, 3), (1, 4, 2)],
[(1, 1, 3), (1, 4, 3)],
[(1, 1, 3), (1, 4, 4)],
[(1, 1, 3), (1, 4, 5)],
[(1, 1, 3), (1, 4, 6)],
...]
How it works -
Create itertools.product using ranges for color and shape. This gives you all possible (color, shape) tuples.
For permutation order 1 to m (1, 2, 3, ..., m) permute over this list of all possible tuples k times where 1>=k>=m
Use list(zip(*i)) on each generated permutation to transpose it from [(color1, shape1), (color2, shape2), (color3, shape3)] to [(color1, color2, color3), (shape1, shape2, shape3)]
You have a number of parameters:
the number of possible colours (for example, 2)
the number of possible shapes (for example, 3)
the number of colour / shape combinations (for example, 4)
In Python:
n_colours = 2
colours = range(1, n_colours+1)
n_shapes = 3
shapes = range(1, n_shapes+1)
# creating a list of all possible combinations of colours and shapes:
all_pairs = list(product(colours, shapes))
You asked to get the combinations in two separate lists of the colours and the corresponding shapes. It seems more sensible to generate them as tuples of pairs instead:
from itertools import product
max_len = 4
tuples = [t for p in [product(all_pairs, repeat=n) for n in range(1, max_len+1)] for t in p]
But if you wanted to generate them as pairs of separate colours and shapes instead, here's an implementation that generates them one after the other:
from itertools import product
def all_colour_shape_pairs(n_colours, n_shapes, max_len):
ps = list(product(range(1, n_colours+1), range(1, n_shapes+1)))
for t in [t for p in [product(ps, repeat=n) for n in range(1, max_len+1)] for t in p]:
yield zip(*t)
result = all_colour_shape_pairs(2, 3, 4)
while input('Press enter for another, or enter "x" to stop:') != 'x':
print(tuple(next(result)))
Output
((1,), (1,))
((1,), (2,))
((1,), (3,))
((2,), (1,))
...
((2,), (3,))
((1, 1), (1, 1))
((1, 1), (1, 2))
...
((2, 2), (3, 3))
((1, 1, 1), (1, 1, 1))
((1, 1, 1), (1, 1, 2))
...
And if you want the generator to keep generating results "inifinitely" (or rather, to stop when the computer runs out of resources and is unable to continue):
from itertools import product
def all_colour_shape_pairs(n_colours, n_shapes, max_len):
ps = list(product(range(1, n_colours+1), range(1, n_shapes+1)))
n = 1
while True:
for t in product(ps, repeat=n):
yield zip(*t)
n += 1
result = all_colour_shape_pairs(2, 3, 4)
while input('Press enter for another, or enter "x" to stop:') != 'x':
print(tuple(next(result)))

How to I scale a list up in size?

I have a list that looks like this:
[
[(0, 0, 0), (1, 1, 1), (2, 2, 2)],
[(1, 1, 1), (2, 2, 2), (3, 3, 3)],
[(2, 2, 2), (3, 3, 3), (4, 4, 4)]
]
I want to scale it up by 3, so it looks like this:
[
[(0, 0, 0), (0, 0, 0), (0, 0, 0), (1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2)],
[(0, 0, 0), (0, 0, 0), (0, 0, 0), (1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2)],
[(0, 0, 0), (0, 0, 0), (0, 0, 0), (1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2)]
[(1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3)],
[(1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3)],
[(1, 1, 1), (1, 1, 1), (1, 1, 1), (2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3)]
[(2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3), (4, 4, 4), (4, 4, 4), (4, 4, 4)],
[(2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3), (4, 4, 4), (4, 4, 4), (4, 4, 4)],
[(2, 2, 2), (2, 2, 2), (2, 2, 2), (3, 3, 3), (3, 3, 3), (3, 3, 3), (4, 4, 4), (4, 4, 4), (4, 4, 4)]
]
Is there any way to do this that will also work for scale factors other than 3?
numpy has a function to repeat elements in a given axis:
import numpy as np
x = [
[(0, 0, 0), (1, 1, 1), (2, 2, 2)],
[(1, 1, 1), (2, 2, 2), (3, 3, 3)],
[(2, 2, 2), (3, 3, 3), (4, 4, 4)]
]
x = np.repeat(x, 3, axis=0)
x = np.repeat(x, 3, axis=1)

python: perform a generic multi dimensional loop

Python:
How to efficiency execute a multidimensional loop, when the number of indexes to loop is dynamic.
Assume an array var_size containing the size of each variable
var_size = [ 3, 4, 5 ]
and a function 'loop' which will call 'f(current_state)' for each point.
def f(state): print state
loop(var_size, f)
This call would call f in the following order:
f( [ 0, 0, 0])
f( [ 0, 0, 1])
f( [ 0, 0, 2])
f( [ 0, 1, 0])
etc....
You can do this with itertools.product:
>>> print list(itertools.product(*(range(x) for x in reversed([3,4,5]))))
[(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)]
Note that I'm generating tuples instead of lists, but that's easy to fix if you really need to.
So, to me it looks like you want:
map(f,itertools.product(*map(range,reversed(var_size))))
Make a list initialized to 0s, as many entries as are in var_size. We treat this list as a list of 'tumblers' - we increment the last one in the list until it overflows its limit (aka var_size at the same point into the list). If so, we set it to 0, go one left and repeat the increment/overflow check until we either do not overflow (reset the 'which tumbler are we looking at' variable back to the last and continue) or overflow all entries of the list (we're done, we looped all the way around), then perform the next call.
I don't know if this is optimal or pythonic, but it is O(n).
This code does the job - And it has the advantage of not creating the list. However, it not that elegant....
Any ideas on how to get this better?
def loop(var_size, f):
nb = len(var_size)
state = [0]*nb
ok = True
while ok:
f(state)
for i in range(nb-1, -1, -1):
state[i] = state[i]+1
if state[i] < var_size[i]:
break
else:
if i == 0:
ok = False
break
else:
state[i] = 0
var_size = [3,4,5]
def f(state):
print state
loop(var_size, f)

How to use itertools to output results of only a certain length

Suppose I have a list of bytes (x00 to xFF). How can I use itertools to return only permutations that have length of X.
So for example I want all permutations with length 3, then I'll get
[x00,x00,x00], [x00,x00,x01], ..., [xFF,xFF,xFF]
That way there is no waste of computing resources.
EDIT: Doesn't have to be itertools if there is a better way.
import itertools
for tup in itertools.product(range(0x100), repeat=3):
...
It seems #gnibbler's solution is more correct?
In [162]: >>> l = [1, 2, 3]
In [163]: list(itertools.combinations_with_replacement(l, 3))
Out[163]:
[(1, 1, 1),
(1, 1, 2),
(1, 1, 3),
(1, 2, 2),
(1, 2, 3),
(1, 3, 3),
(2, 2, 2),
(2, 2, 3),
(2, 3, 3),
(3, 3, 3)]
In [164]: list(itertools.product(l, repeat=3))
Out[164]:
[(1, 1, 1),
(1, 1, 2),
(1, 1, 3),
(1, 2, 1),
(1, 2, 2),
(1, 2, 3),
(1, 3, 1),
(1, 3, 2),
(1, 3, 3),
(2, 1, 1),
(2, 1, 2),
(2, 1, 3),
(2, 2, 1),
(2, 2, 2),
(2, 2, 3),
(2, 3, 1),
(2, 3, 2),
(2, 3, 3),
(3, 1, 1),
(3, 1, 2),
(3, 1, 3),
(3, 2, 1),
(3, 2, 2),
(3, 2, 3),
(3, 3, 1),
(3, 3, 2),
(3, 3, 3)]
itertools.combinations_with_replacement:
>>> my_list = [1, 2, 3, 4]
>>> import itertools
>>>
>>> list(itertools.combinations_with_replacement(my_list, 3))
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4),
(1, 2, 2), (1, 2, 3), (1, 2, 4),
(1, 3, 3), (1, 3, 4),
(1, 4, 4),
(2, 2, 2), (2, 2, 3), (2, 2, 4),
(2, 3, 3), (2, 3, 4),
(2, 4, 4),
(3, 3, 3), (3, 3, 4),
(3, 4, 4),
(4, 4, 4)]
Seems like you want all the permutations, with replacement. In that case, you need: itertools.product as in #gnibbler's answer.

Is there a way to add multiple conditions in a for loop?

n=int(raw_input('enter the number of mcnuggets you want to buy : ')) #total number of mcnuggets you want yo buy
for a in range(1,n) and b in range(1,n) and c in range(1,n) :
if (6*a+9*b+20*c==n):
print 'number of packs of 6 are ',a
print 'number of packs of 9 are ',b
print 'number of packs of 20 are',c
i am new to programming and i am learning python.the code above gives errors. Any suggestion.?.
You should use nested loops:
for a in range(1, n):
for b in range(1, n):
for c in range(1, n):
if ...
Or even better:
import itertools
for a, b, c in itertools.product(range(1, n + 1), repeat=3):
if ...
I think you should start the ranges from 0, otherwise you will only get answers that include at least one of each size. You can also make less work for the computer since you know that there will never be more than n/6 packs of 6 required etc. This can be a big saving - for 45 nuggets you only need to test 144 cases compared to 97336
from itertools import product
n=int(raw_input('enter the number of mcnuggets you want to buy : ')) #total number of mcnuggets you want to buy
for a,b,c in product(range(n//6+1), range(n//9+1), range(n//20+1)) :
if (6*a+9*b+20*c==n):
print 'number of packs of 6 are ',a
print 'number of packs of 9 are ',b
print 'number of packs of 20 are',c
itertools.product gives the cartesian product of the 3 ranges. For example
>>> from itertools import product
>>> list(product(range(3),range(4),range(5)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 0), (0, 2, 1), (0, 2, 2), (0, 2, 3), (0, 2, 4), (0, 3, 0), (0, 3, 1), (0, 3, 2), (0, 3, 3), (0, 3, 4), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 0, 4), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 1, 4), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 2, 4), (1, 3, 0), (1, 3, 1), (1, 3, 2), (1, 3, 3), (1, 3, 4), (2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 0, 3), (2, 0, 4), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 1, 4), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 2, 4), (2, 3, 0), (2, 3, 1), (2, 3, 2), (2, 3, 3), (2, 3, 4)]
If you want to have values from multiple sequences in a for loop then you can use zip, for example:
for (a,b,c) in zip(xrange(1,n), xrange(1,n), xrange(1,n)) :
....
Of course it is a waste repeating the same range, but judging from the title of your post I guess that using the same range is only and example.

Categories

Resources