-1

I would like to learn how to use list comprehension to find the things like the maximum value within a matrix.

This is a simplified version of what I'd like to do.

max_hourglass = 0
[[max_hourglass = i+j for j in range(4) if j < 3] for i in range(4)]
print(max)

I get a syntax error for the assignment of max. I tried casting i and j to integers just in case this was the problem, however, it doesn't appear to be the case.

The more complicated problem I'm attempting to use this code for is to solve a HackerRank question. I have already solved it, however, I am just attempting to expand my knowledge of python3 by using different techniques to solve the problem. This is the Hackerrank problem.

Here is the more complicated problems code just in case the problem is different for it.

arr = []
for _ in range(6):
   arr.append([int(num) for num in input().split()])

max_hourglass = 0
for i in range(4):
    for j in range(4):
        hourglass = arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2]
        if hourglass > max_hourglass:
            max_hourglass = hourglass
print(max_hourglass)

As you can see the problem I am trying to reduce to list comprehension is the nested for loops for which I came up with this code with the same logic as the simplified version:

[max_hourglass = (arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2]) for j in range(4) if (arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2]) > max_hourglass] for i in range(4)]

I'm completely aware this is less readable code and I would not use this in production but rather just want to further understand python's list comprehension syntax.

For context, the Hackerrank problem is to find in a 2D array (Matrix) the largest sum of values made up of the shape I of which they denote as an hourglass shape.

e.g.

1 1 1 0 0 0
0 1 0 0 0 0
1 1 1 0 0 0
0 0 2 4 4 0
0 0 0 2 0 0
0 0 1 2 4 0

Would result in the output 19 as the values:

2 4 4
  2  
1 2 4

add up to 19.

joshuatvernon
  • 1,099
  • 2
  • 19
  • 36
  • 1
    By `max = ...` do you mean `max(...)`? – TigerhawkT3 Nov 11 '16 at 01:55
  • 2
    You cannot do assignments in list comprehension. Just simple do `[i+j...]` – Christian Dean Nov 11 '16 at 01:55
  • 1
    It seems to me that if you're writing code for some kind of competition, you should accomplish it on your own merit and abilities, about which a question about basic syntax speaks volumes. – TigerhawkT3 Nov 11 '16 at 01:57
  • FWIW, Python has a versatile and efficient built-in function named [`max`](https://docs.python.org/3/library/functions.html#max) for calculating maxima, so you shouldn't mask it by calling your own variable `max`. And you should use it when you need to calculate maxima, rather than re-inventing the wheel. For this problem, you should also look at the built-in [`sum`](https://docs.python.org/3/library/functions.html#sum) function. – PM 2Ring Nov 11 '16 at 02:08
  • @TigerhawkT3 I do not mean `max(...)` and understand the poor choice of variable name also it is not a competition but rather a course in which 1 challenge become available each day for 30 days. I completed the task with ease but wanted to go further and learn more about list comprehension to complete the task in a different way. I would not ask questions if it was a competition of which I agree 100% that I should accomplish based on my own merit and abilities. – joshuatvernon Nov 11 '16 at 02:13
  • I have amended the question to rename the variable from `max` to `max_hourglass` as whilst I knew it was not goo practice I didn't realise it would deflect fro the question I asked. I am new to SO and would like to ensure I pose good questions that are informative to future readers. Please advise of any other elements of the question that are found wanting. – joshuatvernon Nov 11 '16 at 02:17
  • It may prove beneficial to you to create functions that calculate a hourglass sum from a submatrix at a certain coordinate – OneCricketeer Nov 11 '16 at 02:24
  • I have amended the title so as to better lead users to the question if they are making the same mistake I was in my approach to using python's list comprehension. Please advise me of any aspects of my use of SO that could be improved upon. Thank you. – joshuatvernon Nov 11 '16 at 02:26
  • @AllDani.com why if it's illegal does the code compile when it's used? I only ask to further understand not to defend my use of it all. – joshuatvernon Nov 11 '16 at 02:32
  • 1
    @AllDani.com - No it isn't. – TigerhawkT3 Nov 11 '16 at 02:33
  • If you want to learn about comprehensions, I recommend reading some instructional material about them rather than making guesses at syntax. Guessing doesn't often work in programming. – TigerhawkT3 Nov 11 '16 at 02:34
  • @TigerhawkT3 I read a few articles including this one http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Comprehensions.html which goes over a lot of the syntax, however, doesn't mention that variable assignment is prohibited in list comprehension. I also only made a "guess" at the syntax in my question to SO to elicit the help of others and express my current understanding of list comprehension. I believe this is the correct use of SO however please advise me if it is not. – joshuatvernon Nov 11 '16 at 02:41
  • 1
    `max = 1 print max(2,3)` throws an error. That means if one codes `max` in as a variable, the next developer will get an error when trying to use the built in function. Correct me if I'm wrong. – Daniel Springer Nov 11 '16 at 02:47
  • I believe @AllDani.com raises a good point. I wanted to understand what would happen when using a reserved word such as `max` so I assigned a value to a variable and named it `max` then attempted to use the function `max` on a list and it gave me the error `TypeError: 'int' object is not callable`. So it could cause issues if you did want to use the `max()` function later on in the code and as such I believe the right thing to do is to never use the variable name `max`. – joshuatvernon Nov 11 '16 at 02:49

3 Answers3

2

List comprehensions are supposed to be used to produce a list. Using them for some sort side effect is discouraged. And in your case of variable assignment, prohibited.

It is in effect a shorthand for

result = []
for ...:
    result.append(...)

If your problem does not fit that mold, it has no business being written as a list comprehension.

It is perfectly good form to construct several list comprehensions; and then apply some function like max to compress the list into one variable.

list1 = [.... for i in list0]
list2 = [.... for j in list1]
mymax = max(list2)

The lists could be replaced with generators and dictionary comprehensions.

Comprehensions encourage you to break the calculation into chunks or building blocks, which are then strung together into more complicated operations.

hpaulj
  • 175,871
  • 13
  • 170
  • 282
  • Thank you, I did not realise variable assignment was prohibited in list comprehension and as I am new to using it I had only an inkling to its potential and correct practices. I shall endeavour to use it in the future to only produce a list. – joshuatvernon Nov 11 '16 at 02:20
1

Here is your list comprehension

arr = []
for _ in range(6):
   arr.append([int(num) for num in input().split()])

max_hourglass = max([arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2] for i in range(4) for j in range(4)])

print(max_hourglass)

Even better:

arr = [[int(num) for num in input().split()] for _ in range(6)]

max_hourglass = max([arr[i][j] + arr[i][j+1] + arr[i][j+2] + arr[i+1][j+1] + arr[i+2][j] + arr[i+2][j+1] + arr[i+2][j+2] for i in range(4) for j in range(4)])

print(max_hourglass)
smac89
  • 26,360
  • 11
  • 91
  • 124
  • 1
    I can see how this is the correct approach by using list comprehension to produce a list of the hourglass values and the using the `max()` function to find the maximum of the hourglass values. Thank you. – joshuatvernon Nov 11 '16 at 02:28
1

Given this is from a finished competition...
Using 2 nested list comprehensions, a mask and 2 nested generator expressions:

import itertools as it

data = [[int(x) for x in input().split()] for _ in range(6)]
mask = [(0,0), (0, 1), (0, 2), (1, 1), (2, 0), (2, 1), (2, 2)]
print(max(sum(data[x+dx][y+dy] for dx, dy in mask)
          for x, y in it.product(range(6-3+1), repeat=2)))
AChampion
  • 26,341
  • 3
  • 41
  • 64