I'm working in some Project Euler problems and have a solution I'd like to make more adaptable. The problem itself isn't important here but for those of you that are curious, it's problem 11.
Currently, I have a grid of 20 by 20 integer values and I'm finding the maximum product of 4 adjacent values. It all works fine and pretty quickly. What I currently have is the following:
maxi = 0
amount = 4
for i in range (0,len(grid) - amount):
for j in range (0,len(grid) - amount):
try:
max_dic = {
'right':grid[i][j]*grid[i][j+1]*grid[i][j+2]*grid[i][j+3],
'down':grid[i][j]*grid[i+1][j]*grid[i+2][j]*grid[i+3][j],
'down_right':grid[i][j]*grid[i+1][j+1]*grid[i+2][j+2]*grid[i+3][j+3],
'down_left':grid[i][j]*grid[i+1][j-1]*grid[i+2][j-2]*grid[i+3][j-3]
}
except IndexError:
pass
max_key = str(max(max_dic.items(), key=operator.itemgetter(1))[0])
if max_dic[max_key] > maxi:
maxi = max_dic[max_key]
What I would like to do is replace the values in the dictionary by something I can vary (so something in terms of amount) and I thought of using a for loop to range from 0 to amount-1 which would look like this:
'right': for a in range(amount): # Multiply the correct values
However, I'm not sure whether or not this is possible and if so, how to implement it.
Any advice on how I could do this ?
In your current implementation, you won't get a max_dic
result at all whenever
any of the pieces exceed the grid boundaries. Often in problems like these, you
do indeed want a partial result. If so, you probably want
the ability to handle the IndexError
in a more fine-grained way. For example,
you could create a simple helper function that takes a grid and two indexes and
returns either the value or some default (a 1
in the case of multiplication).
def get_val(grid, i, j, default = 1):
try:
return grid[i][j]
except IndexError:
return default
Once you have that building block, it's just a matter of preparing some lists of indexes and then using a few functions from the standard library:
from operator import mul
from functools import reduce
# Inside your two loops over i and j ...
ms = list(range(i, i + amount))
ns = list(range(j, j + amount))
rns = list(range(j, j - amount, -1))
max_dic = {
'right' : reduce(mul, [get_val(grid, i, n) for n in ns]),
'down' : reduce(mul, [get_val(grid, m, j) for m in ns]),
'down_right' : reduce(mul, [get_val(grid, m, n) for m, n in zip(ms, ns)]),
'down_left' : reduce(mul, [get_val(grid, m, n) for m, n in zip(ms, rns)]),
}