Laura
Laura

Reputation: 45

Slicing, indexing and iterating over 2D numpy arrays

I am enrolled in a beginners class Python at my university. We've got a programming assignment which I'm stuck on.

We got an assignment to find a route between two point in a map, the map is an 2D numpy array. One of the first tasks is to convert the array consisting of free road(1) and buildings(0) to an array where all the locations surrounding a building (left, right, below, above) are converted to parking spots (-1)

I started with writing a function to generate a 2D numpy array in the right size:

def get_map():

    map = np.random.randint(2, size=(12, 10))

    return map

Now I want to write another function that takes the map as an argument, and returns the map where the parking spots are converted from 1's to -1's.

def adjusted_map(map): 

    map_adjusted = 

    return map_adjusted

I am mostly stuck on the elements above and below the 0's. Left and right I can do because that's no different from 1D arrays or normal lists, strings etc. Im sorry if this is a stupid question but I looked into the numpy documentation about indexing, slicing and iterating over numpy arrays, but I could not find a solution for my problem.

Upvotes: 1

Views: 195

Answers (2)

Paul Panzer
Paul Panzer

Reputation: 53089

Here is one simple way using standard numpy techniques:

1) Make a map consisting of 3x3 blocks with 80% road

>>> map_ = np.kron(np.random.random((6, 5)) < 0.8, np.ones((3, 3), int))
>>> map_
array([[1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0]])

2) Invert the map and zero-pad it

>>> helper = np.pad(1-map_, ((1, 1), (1, 1)), 'constant')
>>> helper
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

3) Cut out shifted versions (up, down, left, right) of the inverse map, use (bitwise) or to find all neighbors of buildings, use and to only keep neighbors that are road

>>> parking = map_ & (helper[2:, 1:-1] | helper[:-2, 1:-1] | helper[1:-1, 2:] | helper[1:-1, :-2])
>>> parking
array([[0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0]])

4) Mark the parking spots on the map

>>> result = map_ - 2*parking
>>> result
array([[ 1,  1, -1,  0,  0,  0,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 1,  1, -1,  0,  0,  0,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 1,  1, -1,  0,  0,  0,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 1,  1, -1,  0,  0,  0, -1, -1, -1,  1,  1,  1,  1,  1,  1],
       [ 1,  1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1,  1,  1,  1],
       [-1, -1, -1,  0,  0,  0, -1, -1, -1,  1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1, -1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1,  1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1,  1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1,  1,  1, -1, -1, -1,  1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
       [ 0,  0,  0, -1,  1,  1, -1, -1, -1,  1,  1,  1,  1,  1,  1],
       [-1, -1, -1,  1,  1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [ 1,  1,  1,  1,  1, -1,  0,  0,  0, -1,  1,  1,  1,  1,  1],
       [-1, -1, -1,  1,  1, -1,  0,  0,  0, -1,  1,  1, -1, -1, -1],
       [ 0,  0,  0, -1,  1, -1,  0,  0,  0, -1,  1, -1,  0,  0,  0],
       [ 0,  0,  0, -1,  1, -1,  0,  0,  0, -1,  1, -1,  0,  0,  0],
       [ 0,  0,  0, -1,  1, -1,  0,  0,  0, -1,  1, -1,  0,  0,  0]])

5) Bonus: Prettify

>>> symbols = np.array(('x', '.', 'P'))
>>> rowtype = f'U{map_.shape[1]}'
>>> rowtype
'U15'
>>> print('\n'.join(symbols[map_].view(rowtype).ravel()))
...xxxxxx......
...xxxxxx......
...xxxxxx......
...xxx.........
...xxx.........
...xxx.........
xxx...xxx......
xxx...xxx......
xxx...xxx......
xxx............
xxx............
xxx............
......xxx......
......xxx......
......xxx......
xxx...xxx...xxx
xxx...xxx...xxx
xxx...xxx...xxx
>>> print('\n'.join(symbols[result].view(rowtype).ravel()))
..PxxxxxxP.....
..PxxxxxxP.....
..PxxxxxxP.....
..PxxxPPP......
..PxxxP........
PPPxxxPPP......
xxxPPPxxxP.....
xxxP.PxxxP.....
xxxP.PxxxP.....
xxxP..PPP......
xxxP...........
xxxP..PPP......
PPP..PxxxP.....
.....PxxxP.....
PPP..PxxxP..PPP
xxxP.PxxxP.Pxxx
xxxP.PxxxP.Pxxx
xxxP.PxxxP.Pxxx

Upvotes: 2

Yuca
Yuca

Reputation: 6101

so you need something like this:

import numpy as np

mapper = np.random.randint(2, size=(12, 10))
buildings = np.nonzero(mapper)

nonzero_row = buildings[0]
nonzero_col = buildings[1]

for row, col in zip(nonzero_row, nonzero_col):
    if row > 0:
        mapper[row-1, col] = -1
    if col > 0:
        mapper[row, col-1] = -1
    if row < mapper.shape[0]:
        mapper[row+1,col] = -1
    if col < mapper.shape[1]:
        mapper[row,col+1] = -1

Upvotes: 0

Related Questions