Inverse generator instead of list of locations from 2d array

Yesterday I worked on a game where I had to cross a two-dimensional array and find the location of any cells marked "d" (where the cells are represented as "-" for empty or "d" for dirty).

I did this using two for-loops:

def find_dirty_cells(board): dirty_cells = [] for enum, row in enumerate(board): for enumrow, cell in enumerate(row): if cell == 'd': dirty_cells.append((enum, enumrow)) return dirty_cells 

But then I thought it was better to build a generator object and return it instead, so I wrote the following:

 def find_dirty_cells(board): return ((enum, enumrow) for enumrow, cell in enumerate(row) for enum, row in enumerate(board) if cell == 'd') 

But the second gives me the wrong data in response (that is, it does not find the cell "d"). There must be something simple, I miss, which makes the second not equal to the first, but I do not see it. The real question I was trying to solve is this: is there an easy way to make my first attempt to return the generator?

+4
source share
3 answers

You need to specify the for loops in the same order in which you nest them:

 def find_dirty_cells(board): return ((enum, enumrow) for enum, row in enumerate(board) for enumrow, cell in enumerate(row) if cell == 'd') 

You swapped the enumerate(board) and enumerate(row) loops, which will only work if there is a global row variable in your session or in your module.

In this case, it might be easier to just use the generator function instead of the generator expression, using yield instead of dirty_cells.append() :

 def find_dirty_cells(board): for enum, row in enumerate(board): for enumrow, cell in enumerate(row): if cell == 'd': yield enum, enumrow 

This will have the same effect, but perhaps more readable.

+3
source

To purely convert the original function into a generator, you want yield rather than return (or in your particular case, not append ). I would prefer this version of the generator expression version because the original is much more readable .

 def find_dirty_cells(board): for enum, row in enumerate(board): for enumrow, cell in enumerate(row): if cell == 'd': yield (enum, enumrow) 
+3
source

This is an easy way to do this with numpy.ndenumerate() :

 from numpy import ndenumerate find_dirty_cells = lambda a: (i for i,v in ndenumerate(a) if v=='d') 

and this will work for an array with more than two dimensions.

+1
source

Source: https://habr.com/ru/post/1489118/


All Articles