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)]
(...)
Related
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)]
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)]]
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)]
How would one go about generating a graph-like object (in R or Python) representing a regular rectangular network of connected hexagons, like in the following image:
Vertices at the "center" of the graph should each have 6 edges, and vertices at the "sides" of the graph should have either 2, 3 or 5 edges.
You can create a grid of adjacency sets representing the indices of the cells each individual cell is connected with:
class HexGraph:
def __init__(self, rows, cols):
self.rows = rows
self.cols = cols
self.cells = [[set() for c in range(self.cols)] for r in range(self.rows)]
self.build_connections()
def build_connections(self):
offsets = (((-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (1, -1)),
((-1, 0), (1, 0), (0, -1), (0, 1), (-1, 1), (1, 1)))
for rdx, line in enumerate(self.cells):
for cdx, cell in enumerate(line):
for dr, dc in offsets[rdx % 2]:
r = rdx + dr
c = cdx + dc
if r >= 0 and r < self.rows and c >= 0 and c < self.cols:
cell.add((r, c))
def __str__(self):
result = []
for line in self.cells:
res = ''
for cell in line:
res += str(cell) + ', '
result.append(res)
return '\n'.join(result)
if __name__ == '__main__':
g = HexGraph(5, 4)
print(g)
output:
{(0, 1), (1, 0)}, {(0, 2), (1, 0), (0, 0), (1, 1)}, {(1, 2), (0, 3), (0, 1), (1, 1)}, {(1, 2), (1, 3), (0, 2)},
{(0, 1), (0, 0), (2, 1), (2, 0), (1, 1)}, {(0, 1), (1, 2), (2, 1), (2, 2), (1, 0), (0, 2)}, {(1, 3), (0, 2), (2, 3), (2, 2), (0, 3), (1, 1)}, {(1, 2), (0, 3), (2, 3)},
{(3, 0), (1, 0), (2, 1)}, {(3, 0), (3, 1), (2, 0), (2, 2), (1, 0), (1, 1)}, {(1, 2), (3, 2), (3, 1), (2, 1), (2, 3), (1, 1)}, {(1, 2), (3, 2), (1, 3), (3, 3), (2, 2)},
{(3, 1), (2, 1), (2, 0), (4, 1), (4, 0)}, {(3, 2), (3, 0), (2, 1), (2, 2), (4, 2), (4, 1)}, {(3, 3), (3, 1), (2, 3), (4, 3), (2, 2), (4, 2)}, {(3, 2), (2, 3), (4, 3)},
{(3, 0), (4, 1)}, {(3, 0), (4, 2), (3, 1), (4, 0)}, {(3, 2), (3, 1), (4, 1), (4, 3)}, {(4, 2), (3, 2), (3, 3)},
It corresponds to the connections between nodes in the image you posted, with each second row pulled a bit to the left to align vertically with the nodes directly above & under it.
Please pardon the poor quality drawing.
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)]]