6

I've read that one of the key beliefs of Python is that flat > nested. However, if I have several variables counting up, what is the alternative to multiple for loops? My code is for counting grid sums and goes as follows:

def horizontal():
    for x in range(20):
        for y in range(17):
            temp = grid[x][y: y + 4]
            sum = 0
            for n in temp:
                sum += int(n)
            print sum # EDIT: the return instead of print was a mistype

This seems to me like it is too heavily nested. Firstly, what is considered to many nested loops in Python ( I have certainly seen 2 nested loops before). Secondly, if this is too heavily nested, what is an alternative way to write this code?

davenz
  • 399
  • 2
  • 3
  • 9

3 Answers3

16
from itertools import product

def horizontal():
    for x, y in product(range(20), range(17)):
        print 1 + sum(int(n) for n in grid[x][y: y + 4])

You should be using the sum function. Of course you can't if you shadow it with a variable, so I changed it to my_sum

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • I'd use `xrange` instead of `range`. I'd also agree that the `return` inside the loop is a bug. –  Dec 17 '12 at 05:07
  • 2
    @Balthamos, for small ranges, `range` is faster, and there is no `xrange` in Python3. OP doesn't mention which version they are using – John La Rooy Dec 17 '12 at 05:08
  • You can just stick the return at the sum calculation line. As you correctly noted, return will stop execution and the next statement after the call will be executed. Since there is no need for the `my_sum` variable (it can't be used after the return call), there is no need to declare it. In short, `return 1 + sum(int(n) for n in grid[x][y: y + 4])` – Burhan Khalid Dec 17 '12 at 05:16
  • @BurhanKhalid, OP clarified that it should just be a `print` there – John La Rooy Dec 17 '12 at 05:17
  • Ah, okay. Not recommended to print stuff in methods as the final result. This causes the method to return `None` and surprises if you do `print horizontal()` – Burhan Khalid Dec 17 '12 at 05:20
  • This section of code is not finished yet. The print is just checking that it is doing all sums, and later I will have it only return the highest – davenz Dec 17 '12 at 05:25
  • @davenz, The `max` function can help you with that. You just need to shift things around a little – John La Rooy Dec 17 '12 at 05:29
1
grid = [range(20) for i in range(20)]
sum(sum( 1 + sum(grid[x][y: y + 4]) for y in range(17)) for x in range(20))

The above outputs 13260, for the particular grid created in the first line of code. It uses sum() three times. The innermost sum adds up the numbers in grid[x][y: y + 4], plus the slightly strange initial value sum = 1 shown in the code in the question. The middle sum adds up those values for the 17 possible y values. The outer sum adds up the middle values over possible x values.

If elements of grid are strings instead of numbers, replace
sum(grid[x][y: y + 4])
with
sum(int(n) for n in grid[x][y: y + 4]

James Waldby - jwpat7
  • 8,593
  • 2
  • 22
  • 37
0

You can use a dictionary to optimize performance significantly

This is another example:

locations = {}
for i in range(len(airports)):
    locations[airports["abb"][i][1:-1]] = (airports["height"][i], airports["width"][i])

for i in range(len(uniqueData)):
    h, w = locations[uniqueData["dept_apt"][i]]
    uniqueData["dept_apt_height"][i] = h
    uniqueData["dept_apt_width"][i] = w
Jakub Bares
  • 159
  • 1
  • 11