You are reading a single comment by @lf and its replies. Click here to read the full conversation.
  • Very C-like, I ended up writing

    def trees(grid, r, d):
        return sum(row[(i*r) % len(row)] == "#"
                   for i, row in enumerate(grid[::d]))
    

    for the find-trees function.

  • were you saying my function was very C-like?

    i've actually just re-written it and it's almost bang on the same as yours with enumerate - had seen a few people talking about that so tried to get that working. still not entirely sure what the :: does in grid[::d], apart from take every d'th y.

    my function:

    def findTrees2(funcdata, dx, dy):
        numTrees = 0
        for i, line in enumerate(funcdata[::dy]):
            if line[(i*dx) % len(line)] == '#': numTrees += 1
        return numTrees
    

    edit: was also confused as to why you can't print an enumerate object until you put it into a list. but guess that's a conversation for data structures... i should really do a bit more formal learning

  • were you saying my function was very C-like?

    Yeah, in the sense of explicit iteration variables for i in range(...).

    foo[::d] is shorthand for foo[slice(None, None, d)] so it's indexing with a slice object with a stride of d.

    was also confused as to why you can't print an enumerate object until you put it into a list

    Iterations over objects in python3 almost always produce generators, which are objects that you can iterate over but produce their results lazily.

    Imagine that the code you had written did something like:

    for i, line in enumerate(funcdata[::dy]):
       if line == "something":
          break # exit early
    

    With an eager generator, you have to make all the pairs to iterate over only to discard most of them when you exit early. With a lazy generator, you can avoid that (and can even deal with an infinite stream of data as long as you terminate at some point).

  • still not entirely sure what the :: does in grid[::d], apart from take every d'th y

    The slice syntax is

    grid[start:stop:stride]
    

    and you can omit any, so start defaults to zero, stop to -1 (which means the end, since negative indices count backwards), and stride defaults to 1.

    • grid[start] just gives you the element at index start (ie, the half-open interval [start,start+1) in maths language),
    • [start:stop] gives you the sub-sequence/sub-string with default stride 1,
    • [start::stride] would give you every stride'th element from start to the end, etc.
About

Avatar for lf @lf started