Python generate all n-permutations of n lists - python

I have n lists of different lengths of wich I want to create all possible permutations.
so e.g. if a=[1,2] and b=[3,4,5] then I would love to obtain res=[[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]]
I've been trying to achieve this using a recursive function, which turned out to be neither very efficient nor very pythonic.
How would an experienced python programmer tackle the problem?

It's called the Cartesian product of two sequences.
This is already available in Python as a library function: itertools.product.
Example:
>>> import itertools
>>> a = [1, 2]
>>> b = [3, 4, 5]
>>> list(itertools.product(a, b))
[(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]

you can do this by product function in itertools,
import itertools
a = [1,2]
b = [3, 4, 5]
out = list(itertools.product(a,b))
print out
[(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]

itertools is definitely the way to go but if you don't want to go the easy route.....
def print_permutations(lists, perms=[]):
if not lists:
print perms
else:
current_layer = lists[0]
remaining_layers = lists[1:]
for word in current_layer:
print_permutations(remaining_layers, perms + [word])
l = (('quick', 'lazy'), ('brown', 'black', 'grey'), ('fox', 'dog'))
print_permutations(l)

Related

How to I calculate permutations without memory problems

Hello I need all permutations of a List l = [1,2,...,n] with length m.
from itertools import permutations
def calcPerm(l:list,m: int)
perm=[]
for i in permutations(l, m):
perm.append(list((i)))
But like u see for n great enough the memory will explode.
Is there a way where I do not have to save does permutations, so i can use every single one
immediately but not get them twice( e.g [1,2] and [2,1] ?
You must use combinations instead of permutations:
from itertools import combinations, permutations
my_list = [1,2,3]
print(list(permutations(my_list, 2)))
#[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
print(list(combinations(my_list, 2)))
#[(1, 2), (1, 3), (2, 3)]
Use itertools.combinations and to save memory use yield:
from itertools import combinations
def calcPerm(l: list, m: int):
for i in combinations(l, m):
yield list((i))
for p in calcPerm(range(10), 5):
print(p)

How to i make "rows" consiting of pairs from a list of objects that is sorted based on their attributes

I have created a class with attributes and sorted them based on their level of x, from 1-6. I then want to sort the list into pairs, where the objects with the highest level of "x" and the object with the lowest level of "x" are paired together, and the second most and second less and so on. If it was my way it would look like this, even though objects are not itereable.
for objects in sortedlist:
i = 0
row(i) = [[sortedlist[i], list[-(i)-1]]
i += 1
if i => len(sortedlist)
break
Using zip
I think the code you want is:
rows = list(zip(sortedList, reversed(sortedList)))
However, note that this would "duplicate" the elements:
>>> sortedList = [1, 2, 3, 4, 5]
>>> list(zip(sortedList, reversed(sortedList)))
[(1, 5), (2, 4), (3, 3), (4, 2), (5, 1)]
If you know that the list has an even number of elements and want to avoid duplicates, you can instead write:
rows = list(zip(sortedList[:len(sortedList)//2], reversed(sortedList[len(sortedList)//2:])))
With the following result:
>>> sortedList = [1,2,3,4,5,6]
>>> list(zip(sortedList[:len(sortedList)//2], reversed(sortedList[len(sortedList)//2:])))
[(1, 6), (2, 5), (3, 4)]
Using loops
Although I recommend using zip rather than a for-loop, here is how to fix the loop you wrote:
rows = []
for i in range(len(sortedList)):
rows.append((sortedList[i], sortedList[-i-1]))
With result:
>>> sortedList=[1,2,3,4,5]
>>> rows = []
>>> for i in range(len(sortedList)):
... rows.append((sortedList[i], sortedList[-i-1]))
...
>>> rows
[(1, 5), (2, 4), (3, 3), (4, 2), (5, 1)]

Getting all possible combinations from a list with duplicate elements?

I have list with repeated elements, for example array = [2,2,2,7].
If I use the solution suggested in this answer (using itertools.combinations()), I get:
()
(7,)
(2,)
(2,)
(2,)
(7, 2)
(7, 2)
(7, 2)
(2, 2)
(2, 2)
(2, 2)
(7, 2, 2)
(7, 2, 2)
(7, 2, 2)
(2, 2, 2)
(7, 2, 2, 2)
As you can see some of the 'combinations' are repeated, e.g. (7,2,2) appears 3 times.
The output I would like is:
()
(7,)
(2,)
(7, 2)
(2, 2)
(7, 2, 2)
(2, 2, 2)
(7, 2, 2, 2)
I could check the output for repeated combinations but I don't feel like that is the best solution to this problem.
You can take the set of the combinations and then chain them together.
from itertools import chain, combinations
arr = [2, 2, 2, 7]
list(chain.from_iterable(set(combinations(arr, i)) for i in range(len(arr) + 1)))
# [(), (7,), (2,), (2, 7), (2, 2), (2, 2, 2), (2, 2, 7), (2, 2, 2, 7)]
You would need to maintain a set of tuples that are sorted in the same fashion:
import itertools as it
desired=set([(),(7,),(2,),(7, 2),(2, 2),(7, 2, 2),(2, 2, 2),(7, 2, 2, 2)])
result=set()
for i in range(len(array)+1):
for combo in it.combinations(array, i):
result.add(tuple(sorted(combo, reverse=True)))
>>> result==desired
True
Without using itertools.combinations() and set's:
from collections import Counter
import itertools
def powerset(bag):
for v in itertools.product(*(range(r + 1) for r in bag.values())):
yield Counter(zip(bag.keys(), v))
array = [2, 2, 2, 7]
for s in powerset(Counter(array)):
# Convert `Counter` object back to a list
s = list(itertools.chain.from_iterable(itertools.repeat(*mv) for mv in s))
print(s)
I believe your problem could alternatively be stated as finding the power set of a multiset, at least according to this definition.
However it's worth noting that the method shown above will be slower than the solutions in other answers such as this one which simply group the results from itertools.combinations() into a set to remove duplicates, despite being seemingly less efficient, it is still faster in practice as iterating in Python is much slower than in C (see itertoolsmodule.c for the implementation of itertools.combinations()).
Through my limited testing, the method shown in this answer will outperform the previously cited method when there are approximately 14 distinct elements in your array, each with an average multiplicity of 2 (at which point the other method begins to pull away and run many times slower), however the running time for either method under those circumstances are >30 seconds, so if performance is of concern, then you might want to consider implementing this part of your application in C.

Python: Print a generator expression's values when those values are itertools.product objects

I'm trying to dig into some code I found online here to better understand Python.
This is the code fragment I'm trying to get a feel for:
from itertools import chain, product
def generate_groupings(word_length, glyph_sizes=(1,2)):
cartesian_products = (
product(glyph_sizes, repeat=r)
for r in range(1, word_length + 1)
)
Here, word_length is 3.
I'm trying to evaluate the contents of the cartesian_products generator. From what I can gather after reading the answer at this SO question, generators do not iterate (and thus, do not yield a value) until they are called as part of a collection, so I've placed the generator in a list:
list(cartesian_products)
Out[6]:
[<itertools.product at 0x1025d1dc0>,
<itertools.product at 0x1025d1e10>,
<itertools.product at 0x1025d1f50>]
Obviously, I now see inside the generator, but I was hoping to get more specific information than the raw details of the itertools.product objects. Is there a way to accomplish this?
if you don't care about exhausting the generator, you can use:
list(map(list,cartesian_products))
You will get the following for word_length = 3
Out[1]:
[[(1,), (2,)],
[(1, 1), (1, 2), (2, 1), (2, 2)],
[(1, 1, 1),
(1, 1, 2),
(1, 2, 1),
(1, 2, 2),
(2, 1, 1),
(2, 1, 2),
(2, 2, 1),
(2, 2, 2)]]

How do I organise a nested list representing coordinate-values to a coordinate-list

I would like to change my data-structure that get from my data-files in such a way that I get a list of all coordinate-values for every coordinates (so a list for all coordinates filled with values)
e.g.
for i in range (files):
open file
file_output = [[0,4,6],[9,4,1],[2,5,3]]
second loop
file_output = [[6,1,8],[4,7,3],[3,7,0]]
to
coordinates = [[0,6],[4,1],[6,8],[9,4],[4,7],[1,3],[2,3],[5,7],[3,0]]
It should be noted that I use over 1000 files of this format, which I should merge.
You could also explore the built-in zip() function
>>> l = []
>>> for k,v in zip(a,b):
l.append(zip(k,v))
>>> print l
[[0,6],[4,1],[6,8],[9,4],[4,7],[1,3],[2,3],[5,7],[3,0]]
>>> a = [[0,4,6],[9,4,1],[2,5,3]]
>>> b = [[6,1,8],[4,7,3],[3,7,0]]
>>> from itertools import chain
>>> zip(chain(*a),chain(*b))
[(0, 6), (4, 1), (6, 8), (9, 4), (4, 7), (1, 3), (2, 3), (5, 7), (3, 0)]
>>>
This should be useful.
[zip(i,j) for i in a for j in b]
However it provides list of tuples, which should satisfy your needs.
If there will only be two lists, you can use this as well.
[[i, j] for i in a for j in b]

Categories