Project Euler #11 logic - python

I have started to play around with Project Euler, however i hit a roadblock at problem 11
What is the greatest product of four adjacent numbers in the same
direction (up, down, left, right, or diagonally) in the 20×20 grid?`
There probably is a bug in my logic somewhere but even after multiple breaks and new approaches, i still have had no success.
The correct output should be 70600674 but i get 51267216.
This is more of an educational question, I would like to at least know where i messed up.
input.txt:
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
Main.py:
in_file = 'input.txt'
m = list(map(lambda line_str: list(map(int, line_str.split(' '))), open(in_file, 'r').read().split('\n')))
for line in m:
print(' '.join(map(lambda num: str(num).rjust(2), line)))
print()
vertical_max = horizontal_max = main_diag_max = second_diag_max = 0
for line in range(17):
for col in range(20):
vertical_max = max(vertical_max, m[line][col] * m[line+1][col] * m[line+2][col] * m[line+3][col])
for line in range(20):
for col in range(17):
horizontal_max = max(horizontal_max, m[line][col] * m[line][col+1] * m[line][col+2] * m[line][col+3])
for line in range(17):
for col in range(17):
main_diag_max = max(main_diag_max, m[line][col] * m[line+1][col+1] * m[line+2][col+2] * m[line+3][col+3])
for line in range(3, 20):
for col in range(3, 20):
second_diag_max = max(second_diag_max, m[line][col] * m[line-1][col-1] * m[line-2][col-2] * m[line-3][col-3])
print('max vertical: ', vertical_max)
print('max horizontal: ', horizontal_max)
print('max main diagonal: ', main_diag_max)
print('max secondary diagonal:', second_diag_max)
print('max result: ', max(vertical_max, horizontal_max, main_diag_max, second_diag_max))

For the second diagonal, your code should be:
for line in range(3, 20):
for col in range(17):
second_diag_max = max(second_diag_max, m[line ][col ] *
m[line-1][col+1] *
m[line-2][col+2] *
m[line-3][col+3])
The problem was that instead of increasing col while decreasing line you were decreasing both. That was essentially checking main diagonal again, but from the opposite direction.

Related

Python perceives each digit in a list as a separate number

I am trying to solve problem 11 in Project Euler. I have got 20x20 grid:
numbers = '''08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48'''
numbers = numbers.strip().split('\n')
But when I do print(numbers[0][0]) it prints only 0, not 08. Thus, I can not normally convert strings into integers. How to make Python perceive numbers as one number, not every digit as a number?
Try a list comprehension:
numbers = '''08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48'''
numbers = [int(i) for i in numbers.strip().split()]
print(numbers)

Input data from file to 2D array in python

I have a file 'input.dat' with the following data (20x20 matrix):
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
How do I put this data from "input.dat" to a 20x20 2D array in python?
You can use a number of libraries including numpy.genfromtxt
import numpy as np
data = np.genfromtxt('input.dat')
Similarly you could use pandas.read_csv
In vanilla python:
arr = []
with open("input.dat", "r") as file:
for line in file:
arr.append(line.split())
Note: While this works just fine for small files, CoryKramer's answer is more suitable for larger inputs.
Using a list comprehension to split each row on whitespace with split():
with open("input.dat") as f:
array = [row.split() for row in f]
print(array)
Output:
[['08', '02', '22', '97', '38', '15', '00', '40', '00', '75', '04', '05', '07', '78', '52', '12', '50', '77', '91', '08'], ['49', '49', '99', '40', '17', '81'...]]

Project Euler # 11 Numpy way

Largest product in a grid
Problem 11
In the 20×20 grid below, four numbers along a diagonal line have been marked in red.
The product of these numbers is 26 × 63 × 78 × 14 = 1788696.
What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?
x ='''
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
'''
import numpy as np
import pandas as pd
arr = np.array(list((x.split())), dtype = int)
arr = arr.reshape(20,20)
arr_m = np.zeros((20,20))
A method loop over elements
%%time
for i in range(0, 17):
for j in range(0, 17):
x = [k for k in range(i, i+4)]
y = [k for k in range(j, j+4)]
arr_m[i,j] = max(arr[i,j: j+4].prod(), arr[i:i+4,j].prod(), arr[x, y].prod(),)
print(arr_m.max())
A method loop over rows, columns and sub-arrys
arr1 = np.zeros((20, 20), dtype=int)
arr2 = np.zeros((20, 20), dtype=int)
arr3 = np.zeros((20, 20), dtype=int)
%%time
for i in range(0, 20):
arr1[:, i] = arr[:, i: i+4].prod(1)
for i in range(0, 20):
arr2[i, :] = arr[i:i+4, :].prod(0)
for i in range(0, 20):
for j in range(0, 20):
arr3[i,j] = arr[i: i+4, j: j+4].diagonal().prod()
max(arr1.max(), arr2.max(), arr3.max())
I want to push it a little bit.
is there any pure numpy or pandas ways to do it without loops?
Here is an approach using stride_tricks. It creates windowed views along all relevant directions and then just multiplies and finds the index of the best value.
The rest is just a bit of book keeping to recover the indices in the original grid.
import numpy as np
x = '''08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
'''
arr = np.array(list((x.split())), dtype = int)
arr = arr.reshape(20,20)
I, J = arr.shape
S, T = arr.strides
horz = np.lib.stride_tricks.as_strided(arr, (I, J-3, 4), (S, T, T)).prod(axis=2)
vert = np.lib.stride_tricks.as_strided(arr, (I-3, J, 4), (S, T, S)).prod(axis=2)
tlbr = np.lib.stride_tricks.as_strided(arr, (I-3, J-3, 4), (S, T, S+T)).prod(axis=2)
bltr = np.lib.stride_tricks.as_strided(arr[3:], (I-3, J-3, 4), (S, T, -S+T)).prod(axis=2)
all_ = horz, vert, tlbr, bltr
midx = [np.unravel_index(o.argmax(), o.shape) for o in all_]
mval = [o[idx] for o, idx in zip(all_, midx)]
hy, hx, vy, vx, ty, tx, by, bx = np.ravel(midx)
a = np.arange(4)
idx = list(map(tuple, np.reshape(np.s_[hy, hx:hx+4, vy:vy+4, vx, ty+a, tx+a, by+a[::-1], bx+a], (4, 2))))
for name, I, V in zip('horizontal vertical topleft-bottomright bottomleft-topright'.split(), idx, mval):
print('best', name, ':', V, '=', ' x '.join(map(str, arr[I])))
Output:
best horizontal : 48477312 = 78 x 78 x 96 x 83
best vertical : 51267216 = 66 x 91 x 88 x 97
best topleft-bottomright : 40304286 = 94 x 99 x 71 x 61
best bottomleft-topright : 70600674 = 87 x 97 x 94 x 89
Numpy accelerate computations, but also and above all give versatile ways to scan the data. To simplify the computation of the useful products, you can :
pad the array with some 0 to simply manage borders.
use a flatten version of the data : then different directions are just different shifts. The 4 directions ar managed in the same logic.
Code :
data = pd.read_clipboard(header=None).values # read the tray
m,n = data.shape
blocksize = 4
arr = np.zeros((m+blocksize,n+1),int) #pad with the right amount of zeros.
arr[:m,:n] = data
flat = arr.ravel()
usefulsize = data.size + m # indice of last non zero value + 1
shifts = [1,n,n+1,n+2] # - / | \ , the four directions
blocks = np.array([[flat[i*s:][:usefulsize] for s in shifts] \
for i in range(blocksize)]) #15µs
scores=blocks.prod(axis=0) #8µs
With smaller "development" time, it's ~200x faster than loops. Output:
print(scores.max())
i,j = np.where(scores==scores.max())
print(blocks[:,i,j])
70600674
[[89][94][97][87]]
My shot would be
def n_prod_max(df, n):
# No rolling(...).prod() or anything out of pandas' box
win_prod = lambda x: x.prod()
# Supposed to be square
df_size = df.shape[0]
diag_nums = pd.Series(range(-df_size + n, df_size - n + 1))
# Columns max
col_max = df.rolling(n).agg(win_prod).max().max()
# Rows max
row_max = df.T.rolling(n).agg(win_prod).max().max()
# Diagonals max
diag_vals = df.values
diag_max = diag_nums.apply(lambda d: pd.Series(diag_vals.diagonal(d))
.rolling(n)
.agg(win_prod)
.max()).max()
# Antidiagonals max
adiag_vals = np.rot90(df.values)
adiag_max = diag_nums.apply(lambda d: pd.Series(adiag_vals.diagonal(d))
.rolling(n)
.agg(win_prod)
.max()).max()
return max([col_max, row_max, diag_max, adiag_max])
>>> n_prod_max(df, 4)
70600674.0

Processing string with numbers causes 'ValueError: invalid literal for int()' error in Python

So basically we are given a text that looks like this:
20
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
It's a 20x20 dimensional square, and you have to figure out the greatest product of four adjacent numbers in the same direction (horizontal, vertical, or diagonal) in a grid of positive integers. This is what I have:
def main():
# open file for reading
in_file = open ("./Grid.txt", "r")
dimension = in_file.readline()
dimensions = int(dimension)
greatest = 0
grid = ''
largest = [0, 0, 0, 0]
for i in range (0, dimensions):
grid = grid + in_file.readline()
grid = grid.strip()
grid = grid.replace(" ","")
i = 0
j = 0
print(int(grid[i]))
for i in range (0, dimensions * 2 + (dimensions - 1)):
for j in range (0, dimensions * 2 + (dimensions - 1) - 3):
if (int(grid[i])*10 + int(grid[i+1]))*(int(grid[i+2])*10 + int(grid[i+3]))*(int(grid[i+4])*10 + int(grid[i+5]))*(int(grid[i+6])*10 + int(grid[i+7])) > largest[0]:
largest[0] = (int(grid[i])*10 + int(grid[i+1]))*(int(grid[i+2])*10 + int(grid[i+3]))*(int(grid[i+4])*10 + int(grid[i+5]))*(int(grid[i+6])*10 + int(grid[i+7]))
print(max(largest))
main()
I know it's super complicated but basically, I'm not sure how to make this set of numbers look like a list of numbers (an array)... So I essentially end up having to make the numbers. For example the first number is 02, so I multiple 0 by 10, and add 2... Anyways, the problem is that I get ValueError: invalid literal for int() with base 10: '\n'. Any help is appreciated!
The problem is this line:
grid = grid + in_file.readline()
Change it to:
grid = grid + in_file.readline().strip() # you must strip each line
You need to strip each line as you read it, but currently, you're stripping only the final string, which leaves all the whitespace you have in each line present. Eventually, your code tries to convert non-numeric characters (e.g. spaces, newlines) into numbers and runs into the error.
After the fix, running it produces the following output:
➜ /tmp ./test.py
0
1614
Additional Recommendations
You definitely need to make your code more readable before posting. It was painful to look at and even more painful to debug... I almost left it there.
One possible start could be in the complicated for loop. Consider:
for i in range (0, dimensions * 2 + (dimensions - 1)):
for j in range (0, dimensions * 2 + (dimensions - 1) - 3):
tmp = int(grid[i]) * 10 \
+ int(grid[i+1]) * int(grid[i+2]) * 10 \
+ int(grid[i+3]) * int(grid[i+4]) * 10 \
+ int(grid[i+5]) * int(grid[i+6]) * 10 \
+ int(grid[i+7])
if tmp > largest[0]:
largest[0] = tmp
First, it allowed me to see that the culprit was int(grid[i+7]) instruction, whereas before it would show the entire line while complaining and was not informative.
Second, it does not calculate exactly the same thing twice. It uses a temporary variable instead.
Third, you should consider converting your grid variable into an actual grid (e.g. an array of arrays). Currently, it's merely a string, so the name is misleading.
Fourth, while you turn grid into an actual grid, you can use a list comprehension and convert the values into numbers directly, as in this short example:
>>> line = '12 34 5 6 78 08 1234'
>>> [int(v) for v in line.split()]
[12, 34, 5, 6, 78, 8, 1234] # array of integers, not strings
>>>
It will save you the conversions before getting to the other parts and validates the data for you in the process while the code is still simpler, instead of waiting to your complicated calculations to blow up.

Clarification on the max() syntax in python

This is in reference to the problem posted in:
http://projecteuler.net/problem=11
I have encountered an oversimplified solution using python as follows:(mayoff)
grid = [[0]*23]*3 + [[int(x) for x in line.split()]+[0,0,0] for line in
'''08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48'''.split('\n')
] + [[0]*23]*3
import operator
print max([reduce(operator.mul, [grid[y+n*d[0]][x+n*d[1]] for n in (0,1,2,3)])
for x in xrange(0,20) for y in xrange(3,23)
for d in ((0,1),(1,0),(1,1),(-1,1))])
The grid is simply a 2-dimensioanl matrix equivalent to the 20x20 matrix given in the problem.
My understanding with the max() function is that it takes a list of integers as an input and then selects from it the maximum value and returns it.
The question is, how come the succeeding for-loops in the last expression are located outside the parameter list in max()? This sounds confusing to me since to create a list using a for-loop we can do it with the following:
>>> line = "12 12 12 12 12 12"
>>> [x for x in line.split()]
['12','12','12','12','12','12']
and doing something similar below would result into an error
>>> [x] for x in line.split()
After your clarification - actually, they are not, if you look better, you have this:
print max(
[
reduce(
operator.mul,
[grid[y+n*d[0]][x+n*d[1]] for n in (0,1,2,3)])
for x in xrange(0,20)
for y in xrange(3,23)
for d in ((0,1),(1,0),(1,1),(-1,1))
])
To reduce some clutter, what you have is this:
print max(
[
reduce(...)
for x in ...
for y in ...
for d in ...
])
i.e.:
print max([reduce(...) for x in ... for y in ... for d in ...])
which is a list comprehension such as the one you gave as an example ([x for x in line.split()] ).
See the documentation:
http://docs.python.org/library/functions.html#max
Excerpt:
max(iterable[, args...][key])
With a single argument iterable, return the largest item of a non-empty iterable (such as a string, tuple or list). With more than one argument, return the largest of the arguments.
You can do e.g. this:
>>> max(1, 2, 3)
3
i.e. run max with a number of parameters and it will give you the maximum of these, or e.g. you can do this:
>>> max([1,2,3])
3
and it will treat it as the iterable and give you the maximum in an iterable. Strings are iterables, so you can do this, too:
>>> max("aqrmn")
'r'
or this:
>>> max(dict(the=1,biggest=-1,word=2,maybe=4,this=0))
'word'
where it considers keys of a dictionary, maybe easier to grasp like this:
>>> max({1:"hey", 5:"man", -3:"how", 7:"are", 3: "you?"})
7
Hope this helps.
>> help(max)
max(...)
max(iterable[, key=func]) -> value
max(a, b, c, ...[, key=func]) -> value
With a single iterable argument, return its largest item.
With two or more arguments, return the largest argument.
That max does return the maximum value. If you want the location do:
a = [reduce(operator.mul, [grid[y+n*d[0]][x+n*d[1]] for n in (0,1,2,3)])
for x in xrange(0,20) for y in xrange(3,23)
for d in ((0,1),(1,0),(1,1),(-1,1))
max_value = max(a)
max_value_position = a.index(max_value)
Not exactly sure what you want. But you did get the maximum value of the list created.

Categories

Resources