How to generate all possible combinations from all permutations? - python

I have a list of all permutations of K elements in Python like this:
import itertools
perms = list(itertools.permutations(range(K), K))
I would like to generate a matrix (or list) M of all possible combinations of these permutations perms. Each element of this matrix (or list) is of size N. How can I do this?
For example, for K=2, I would get perms=[(0, 1), (1, 0)]. For N=3, I would like to have:
M = [ [(0, 1), (0, 1), (0, 1)],
[(0, 1), (0, 1), (1, 0)],
[(0, 1), (1, 0), (0, 1)],
[(0, 1), (1, 0), (1, 0)],
[(1, 0), (0, 1), (0, 1)],
[(1, 0), (0, 1), (1, 0)],
[(1, 0), (1, 0), (0, 1)],
[(1, 0), (1, 0), (1, 0)] ]
M is a list that has 8 lists. Each list is of size N=3 and contains elements from perms.
For N=2, I would like to have:
M = [ [(0, 1), (0, 1)],
[(0, 1), (1, 0)],
[(1, 0), (0, 1)],
[(1, 0), (1, 0)] ]
And for N=1, I would like to have:
M = [ [(0, 1), (1, 0)] ] = perms
I do not know if I formulate my problem correctly (I think it can be re-formulated more clearly than this).

You can use product from itertools.
from itertools import permutations, product
perms = permutations(range(2))
cartesian_tuples = product(perms, repeat=3)
# (((0, 1), (0, 1), (0, 1)),
# ((0, 1), (0, 1), (1, 0)),
# ((0, 1), (1, 0), (0, 1)),
# ((0, 1), (1, 0), (1, 0)),
# ((1, 0), (0, 1), (0, 1)),
# ((1, 0), (0, 1), (1, 0)),
# ((1, 0), (1, 0), (0, 1)),
# ((1, 0), (1, 0), (1, 0)))
You can manually convert individual parts into lists if you need to iterate over anything more than once. The current structure is composed of generators that will be exhausted after one iteration and cannot be used again. If you want nested lists:
cartesian_tuples = map(list, list(product(perms, repeat=3)))
# [[(0, 1), (0, 1), (0, 1)],
# [(0, 1), (0, 1), (1, 0)],
# [(0, 1), (1, 0), (0, 1)],
# [(0, 1), (1, 0), (1, 0)],
# [(1, 0), (0, 1), (0, 1)],
# [(1, 0), (0, 1), (1, 0)],
# [(1, 0), (1, 0), (0, 1)],
# [(1, 0), (1, 0), (1, 0)]]
In Python 3.X, you will have to wrap this in another list call because map(...) returns a map object.
cartesian_tuples = list(map(list, list(product(perms, repeat=3))))
Or, you can avoid all that nonsense and use a list comprehension.
cartesian_tuples = [[perm for perm in prod] for prod in product(perms, repeat=3)]
But it might just be better to create a new iterator each time you need one.
def product_of_permutations(n, k):
return product(permutations(range(k)), repeat=n)

Thinking about it there might be a very simple way to get your desired result using itertools.combinations together with set:
import itertools
K = 2
N = 3
perms = list(itertools.permutations(range(K), K))
# The order matters so we need to copy the list N times
perms = perms*N
# Create the combinations
combs = itertools.combinations(perms, N)
# Only keep unique combinations
M = set(combs)
If you want to have it as list of lists use:
M = [list(i) for i in M]
returns then
[[(1, 0), (0, 1), (0, 1)],
[(1, 0), (1, 0), (1, 0)],
[(0, 1), (0, 1), (1, 0)],
[(0, 1), (1, 0), (1, 0)],
[(0, 1), (0, 1), (0, 1)],
[(0, 1), (1, 0), (0, 1)],
[(1, 0), (0, 1), (1, 0)],
[(1, 0), (1, 0), (0, 1)]]

Related

All possible combinations of a list of tuples

I'm creating "Boggle" in python, and I have a list of tuples that represent coordinates on a game board:
all_coordinates = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2), (0, 3), (1, 3), (2, 3)]
I'm trying to create a new list of lists of tuples that will represent all possible paths on the board.
It'd look something like this:
[[(0,0),(1,0)], ... , [(0,0),(1,0),(2,0),(2,1)] , ... , [(2, 1), (2, 2), (2, 3)], ...]
I tried using itertools.combinations and itertools.permutations but it doesn't seem to do the job, for example the following path:
[(2,1),(1,1),(1,0),(2,0)]
does not appear on the list.
This particular function doesn't necessarily have to output 'valid' paths (valid = moving one step horizontally, vertically or diagonally each time), just all of the possible combinations from the tuples representing the board. I have a function that checks if a certain path returns a valid word. I'm trying to print out all possible paths that return a valid word on the board.
itertools.permutations does indeed produce all the permutations, including the [(2,1),(1,1),(1,0),(2,0)] one that you said was missing. Note that each call to permutations gets you all the permutations of a particular length:
>>> all_coordinates = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2), (0, 3), (1, 3), (2, 3)]
>>> from itertools import permutations
>>> ((2,1),(1,1),(1,0),(2,0)) in permutations(all_coordinates, 4)
True
If you want to see all the permutations from, say, length 2 to length 4, try:
for k in range(2, 5):
for p in permutations(all_coordinates, k):
print(p)
The resulting sequence is very long; as others have pointed out, you might want to come up with another method for generating paths that only include adjacent coordinates (e.g. a breadth-first search).
(edit) Just for fun, here's a very quick DFS approach to building all the paths up to length 4 by looking only at adjacent coordinates:
>>> def print_paths(path):
... print(path)
... if len(path) >= 4:
... return
... x, y = path[-1]
... for dx in range(-1, 2):
... for dy in range(-1, 2):
... c = x + dx, y + dy
... if c not in path and c in all_coordinates:
... print_paths(path + [c])
...
>>> print_paths([(2, 1)])
[(2, 1)]
[(2, 1), (1, 0)]
[(2, 1), (1, 0), (0, 0)]
[(2, 1), (1, 0), (0, 0), (0, 1)]
[(2, 1), (1, 0), (0, 0), (1, 1)]
[(2, 1), (1, 0), (0, 1)]
[(2, 1), (1, 0), (0, 1), (0, 0)]
[(2, 1), (1, 0), (0, 1), (0, 2)]
[(2, 1), (1, 0), (0, 1), (1, 1)]
[(2, 1), (1, 0), (0, 1), (1, 2)]
[(2, 1), (1, 0), (1, 1)]
[(2, 1), (1, 0), (1, 1), (0, 0)]
[(2, 1), (1, 0), (1, 1), (0, 1)]
[(2, 1), (1, 0), (1, 1), (0, 2)]
[(2, 1), (1, 0), (1, 1), (1, 2)]
[(2, 1), (1, 0), (1, 1), (2, 0)]
[(2, 1), (1, 0), (1, 1), (2, 2)]
[(2, 1), (1, 0), (2, 0)]
[(2, 1), (1, 0), (2, 0), (1, 1)]
[(2, 1), (1, 1)]
[(2, 1), (1, 1), (0, 0)]
[(2, 1), (1, 1), (0, 0), (0, 1)]
[(2, 1), (1, 1), (0, 0), (1, 0)]
[(2, 1), (1, 1), (0, 1)]
[(2, 1), (1, 1), (0, 1), (0, 0)]
[(2, 1), (1, 1), (0, 1), (0, 2)]
[(2, 1), (1, 1), (0, 1), (1, 0)]
[(2, 1), (1, 1), (0, 1), (1, 2)]
[(2, 1), (1, 1), (0, 2)]
[(2, 1), (1, 1), (0, 2), (0, 1)]
[(2, 1), (1, 1), (0, 2), (0, 3)]
[(2, 1), (1, 1), (0, 2), (1, 2)]
[(2, 1), (1, 1), (0, 2), (1, 3)]
[(2, 1), (1, 1), (1, 0)]
[(2, 1), (1, 1), (1, 0), (0, 0)]
[(2, 1), (1, 1), (1, 0), (0, 1)]
[(2, 1), (1, 1), (1, 0), (2, 0)]
(...)

Printing all pairs of combinations from a given set of numbers

I'm trying to understand why it is that the combinations of -let's say- 0 and 1 are only: [(0, 0), (0, 1), (1, 1)] and why (1,0) is not included.
The same goes for all the combinations of pairs of 0,1,2,3.
I would like to get: (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)
But my code is only giving me: [(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]
My/the code, which I got from realpython.com/python-itertools/ :
import itertools as com
x = list(com.combinations_with_replacement([0,1,2,3], 2))
How can I edit the code so that it prints all the desired combinations?
You would want to use itertools.product since you want the cartesian product:
>>> import itertools
>>> list(itertools.product([0, 1, 2, 3], repeat=2))
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]
Note you don't want to use itertools.permutations since the output will not contain entries like (0, 0), (1, 1), (2, 2), or (3, 3) since each element in the iterable is only used once.
In order to get all possible combinations, you need to use the product function:
import itertools as com
x = list(com.product([0,1,2,3], repeat=2))
print(x)
As stated in Python docs, this is the same as:
x = [(y,z) for y in [0,1,2,3] for z in [0,1,2,3]]
This will return:
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)]

How to make a list of the coordinates of all columns and rows

Suppose I have a n x n grid, and I want a function that generates a list of all columns and rows by taking n as the input, in python. By a list of columns, I mean each column is represented as its own list, with elements being coordinates of the elements in the column. (Or each column could be a set of coordinates, that would work too)
I could do this using two list comprehensions,
x = [[ (i, j) for j in range(n)] for i in range(n)] + [[ (i, j) for i in range(n)] for j in range(n)]
With n=3 this produces a list with 9 elements, each of which is a list of 3 coordinates.
x = [[(0, 0), (0, 1), (0, 2)], [(1, 0), (1, 1), (1, 2)], [(2, 0), (2, 1), (2, 2)], [(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]
I was wondering if there is a cleaner way to do the same thing, maybe using itertools or a similar module.
Not exactly sure if this is what you're looking for but you could try itertools.product
For example
>>> from itertools import product
>>> n = 3
>>> list(product(range(n),range(n)))
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
>>> [list(product(range(n),range(n)))[n*i:n*i+n] for i in range(n)]
[[(0, 0), (0, 1), (0, 2)], [(1, 0), (1, 1), (1, 2)], [(2, 0), (2, 1), (2, 2)]]
>>> [list(product(range(n),range(n)))[i::n] for i in range(n)]
[[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]

summing tuples in list

I have a list of tuples:
[(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
and I want to sum the right-side of tuples where the left-side is equal, and to put it in another tuples-list, so for the above list i'll get:
[(0,2),(1,1),(2,1),(3,2),(4,3),(5,2)]
I tried this:
k=0
for i,TCtup in enumerate(wordsMatchingList):
if wordsMatchingList[i][0]==k:
TC_matches+=wordsMatchingList[i][1]
print("k: {} /// TC_matches: {}".format(k,TC_matches)) #for checking
else:
groupedWordsMatchingList.append(tuple((k,TC_matches)))
TC_matches=0
k+=1
but from k=1 it just loop one time less for every k because of the else condition.
thank you
If your tuples are guaranteed to come in order like this—all the (0, x), then all the (1, x), etc.—you can use groupby:
>>> xs = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
>>> from itertools import groupby
>>> from operator import itemgetter
>>> groups = groupby(xs, key=itemgetter(0))
>>> ys = [(key, sum(map(itemgetter(1), group))) for key, group in groups]
If they aren't, but you can sort them (you have a list, not just an arbitrary iterable, and it isn't so huge that log-linear time will be too expensive):
>>> groups = groupby(sorted(xs, key=itemgetter(0)), key=itemgetter(0))
If you can't sort them, you can manually build up the totals as you go:
>>> from collections import Counter
>>> totals = Counter()
>>> for k, v in xs:
... totals[k] += v
>>> ys = list(totals.items())
yet another way,
t.sort(key=lambda x: x[0]) #sort before groupby (required)
g=itertools.groupby(t, lambda x: x[0])
new_l = []
for k,v in g:
new_l.append((k, sum([x[1] for x in v])))
Another approach is using a defaultdict (from collections) and to iterate the list of tuples.
from collections import defaultdict
lst = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
d = defaultdict(int)
for (u,v) in lst:
d[u]+=v
# list(d.items()) [(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
I'd recommend using a library with a groupby function. pandas, for instance, can be useful
>>> s = pd.DataFrame(list_)
>>> s.groupby(0, as_index=False).sum().agg(tuple,1).tolist()
[(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
In [5]: [(j, sum([i[1] for i in a if i[0] == j])) for j in set([i[0] for i in a])]
Out[5]: [(0, 2), (1, 1), (2, 1), (3, 2), (4, 3), (5, 2)]
lst = [(0, 1), (0, 1), (0, 0), (0, 0), (1, 0), (1, 0), (1, 1), (1, 0), (1, 0), (2, 0), (2, 1), (2, 0), (3, 0), (3, 1), (3, 1), (3, 0), (3, 0), (4, 0), (4, 1), (4, 0), (4, 1), (4, 1), (5, 0), (5, 0), (5, 1), (5, 1)]
[(i,sum([q[1] for q in lst if q[0] == i])) for i in range(lst[-1][0]+1)]
gives:
[(0,2),(1,1),(2,1),(3,2),(4,3),(5,2)]

Remove zipped pairs with same entries in Python list

I have a list of zipped pairs (for example A)
A = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
What's the best way in which I can remove all pairs where the first and the second entries equal each other (and create a new list)?
In the above example (A), the pairs that I wish to remove are (0, 0), (1, 1) and (2, 2). In this example, I wish the new list to look like this.
A_new = [(0, 1), (0, 6), (0, 7), (1, 3)]
You can use simple list comprehension with if clause that returns True for all unequal pairs that you want to keep:
>>> A = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
>>> [(x, y) for x, y in A if x != y]
[(0, 1), (0, 6), (0, 7), (1, 3)]
using filter, it takes a judge function as first parameter to tell what element to keep and the iterable list as second parameter, lambda defines an anonymous function.
A_new = filter(lambda x: x[0] != x[1], A)
you can do it with list comprehension:
a = [(0, 0), (0, 1), (0, 6), (0, 7), (1, 3), (1, 1), (2, 2)]
final = [k for k in a if k[0] != k[1]]
Output:
print(final)
>>> [(0, 1), (0, 6), (0, 7), (1, 3)]

Categories

Resources