How to change all values to the left of a particular cell in every row

Viewed 68

I have an array which contains 1's and 0's. A very small section of it looks like this:

arr=[[0,0,0,0,1], 
     [0,0,1,0,0],
     [0,1,0,0,0],
     [1,0,1,0,0]]

I want to change the value of every cell to 1, if it is to the left of a cell with a value of 1. I want all other cells to keep their value of 0, i.e:

arrOut=[[1,1,1,1,1], 
     [1,1,1,0,0],
     [1,1,0,0,0]
     [1,1,1,0,0]

Some rows have >1 cell with a value =1.

I have managed to do this using a very ugly double for-loop:

for i in range(len(arr)):
    for j in range(len(arr[i])):
        if arr[i][j]==1:
            arrOut[i][0:j]=1

Does anyone know of another way to do this with using for loops? I'm relatively comfortable with numpy and pandas, but also open to other libraries.

Thanks!

3 Answers

You can flip using it, and use np.cumsum:

>>> arr[:, ::-1].cumsum(axis=1)[:, ::-1]
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0],
       [1, 1, 0, 0, 0]], dtype=int32)

Or the same using np.fliplr,

>>> np.fliplr(np.fliplr(arr).cumsum(axis=1))
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0],
       [1, 1, 0, 0, 0]], dtype=int32)

Using np.where:

>>> np.where(arr.cumsum(1)==0, 1, arr)
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0],
       [1, 1, 0, 0, 0]], dtype=int32)

If array has more than one 1, use np.clip:

>>> arr
array([[0, 0, 0, 0, 1],
       [0, 0, 1, 0, 0],
       [0, 1, 0, 1, 0]])

>>> np.clip(arr[:, ::-1].cumsum(axis=1)[:, ::-1], 0, 1)
 
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0],
       [1, 1, 1, 1, 0]], dtype=int32)

# If you want to make all 0s before the leftmost 1 to 1:
>>> np.where(arr.cumsum(1)==0, 1, arr)

array([[1, 1, 1, 1, 1],
       [1, 1, 1, 0, 0],
       [1, 1, 0, 1, 0]])

A possibility without using libraries:

for subarray in arr:
    #Get the index of the 1 starting from behind so that if there are 2 1s, 
    #you get the index of the rightmost one
    indexof1 = len(subarray) -1 - subarray[::-1].index(1)
    #Until the 1, replace with 1s 
    subarray[:indexof1] = [1]*len(subarray[:indexof1])

Another solution using np.maximum.accumulate:

np.maximum.accumulate(arr[:,::-1],axis=1)[:,::-1]

Where np.maximum.accumulate simply apply a cumulative maximum (cummax).

Related