Clarification on the max() syntax in python - 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.

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)

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

Project Euler #11 logic

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.

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.

Python: I am unable to comprehend the concept of a For Loop, apparently

I've got a list of 400 numbers, and i want to but them in a 20x20 grid using Python.
I've made a "2d array" (not really because Python doesn't support them, I've had to use a list of lists.)
When i try to loop through and assign each subsequnt item to the next box in the grid, it fails. i end up assinging the last item in the list to every box.
Here's the code:
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"
grid = [[0 for col in range(20)] for row in range(20)]
for x in range(0, 1200, 3):
y = x + 2
a = numbers[x:y]
for i in range(20):
for j in range(20):
grid[i][j] = a
print(grid)
I can see why it's going wrong: the two loops that generate the list coordinates are inside the loop that gets each items from the list, so each time they run the value they are assigning doesn't change.
Therefore I guess seeing as they don't work in the loop, they need to be out of it.
The problem is that I can't work out where exactly.
Anyone give me a hand?
This is the sort of thing that list comprehensions are good for.
nums = iter(numbers.split())
grid = [[next(nums) for col in range(20)] for row in range(20)]
Alternatively, as a for loop:
grid = [[0]*20 for row in range(20)]
nums = iter(numbers.split())
for i in xrange(20):
for j in xrange(20):
grid[i][j] = next(nums)
I'm not recommending that you do this, but the way to do it if you don't just want to split the list and then call next on its iterator is to write a generator to parse the list the way that you were and then call next on that. I point this out because there are situations where builtins wont do it for you so you should see the pattern (not Design Pattern, just pattern for the pedantic):
def items(numbers):
for x in range(0, len(numbers), 3):
yield numbers[x:x+2]
nums = items(numbers)
for i in xrange(20):
for j in xrange(20):
grid[i][j] = next(nums)
This lets you step through the two loops in parallel.
Another alternative is to use the grouper idiom:
nums = iter(numbers.split())
grid = zip(*[nums]*20)
Note that this makes a list of tuples, not a list of lists.
If you need a list of lists, then
grid = map(list,zip(*[nums]*20))
Your for loop confusion stems from having more loops than you need.
Instead, one approach is to start by looping over your grid squares and then figuring out the needed offset into your list of numbers:
for i in range(20):
for j in range(20):
offset = i*20*3 + j*3
grid[i][j] = numbers[offset:offset+2]
In this case, the offset has a few constants. i is the row, so for each row you need to skip over a row's worth of characters (60) in your list. j is the column index; each column is 3 characters wide.
You could, of course, do this operation in reverse. In that case, you would loop over your list of numbers and then figure out to which grid square it belongs. It works very similarly, except you'd be using division and modulo arithmetic instead of multiplication in the offset above.
Hopefully this provides some insight into how to use for loops to work with multiple objects and multiple dimensions.

Categories

Resources