简体   繁体   中英

Python: moving all elements greater than 0 to left and right in numpy array

If I have an numpy array like the one below, how can I right justify or left justify the elements tat are greater than zero

[[ 0.  5.  0.  2.]
 [ 0.  0.  3.  2.]
 [ 0.  0.  0.  0.]
 [ 2.  0.  0.  1.]]

for example, If I wanted to right justify this array, it would look like:

[[ 5.  2.  0.  0.]
 [ 3.  2.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 2.  1.  0.  0.]]

One vectorized approach making use of masks -

def justify_rows(a, side='left'):
    mask = a>0
    justified_mask = np.sort(mask,1)
    if side=='left':
        justified_mask = justified_mask[:,::-1]
    out = np.zeros_like(a) 
    out[justified_mask] = a[mask]
    return out

Basically the steps are :

  • Make a mask of greater than zeros.

  • Get a left or right justified mask where greater than elements are to be placed in a zeros initialized array. To get such a justified mask, we simply sort the mask from step-1 along each row, which throws the True ones in each row to the right. Thus, additionally we need flipping of each row for the left justified case.

  • Finally, use the justified mask to assign into output array and the mask from step-1 to select from input array.

Sample runs -

In [105]: a
Out[105]: 
array([[ 0.,  5.,  0.,  2.],
       [ 0.,  0.,  3.,  2.],
       [ 0.,  0.,  0.,  0.],
       [ 2.,  0.,  0.,  1.]])

In [106]: justify_rows(a, side='left')
Out[106]: 
array([[ 5.,  2.,  0.,  0.],
       [ 3.,  2.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 2.,  1.,  0.,  0.]])

In [107]: justify_rows(a, side='right')
Out[107]: 
array([[ 0.,  0.,  5.,  2.],
       [ 0.,  0.,  3.,  2.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  2.,  1.]])

With the assumptions that every row contains at least one zero, and no negatives, this is just a partition:

>>> np.partition(x, 1)
array([[ 0.,  0.,  5.,  2.],
       [ 0.,  0.,  3.,  2.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  2.,  1.]])

Edit: This shuffles the rows, so is little better than a sort

import numpy as np

array = [ 
          [ 0.,  5.,  0.,  2.],
          [ 0.,  0.,  3.,  2.],
          [ 0.,  0.,  0.,  0.],
          [ 2.,  0.,  0.,  1.]
        ]


def move(array, right = True):
  temp = []
  for x in array:
    x = np.array(x)
    #check positive arrays
    if len(np.where(x == 0)[0]) != len(x):
      if right:
        # little faster, compare to [::-1]
        # nonzero on right
        temp.append(x[np.argsort(-x)])
      else:
        # nonzero on left
        temp.append(np.sort(x))
    else:
        # no interchange needed
        temp.append(x)
  return temp

print (move(array, 1))

[array([ 5.,  2.,  0.,  0.]), array([ 3.,  2.,  0.,  0.]), array([ 0.,  0.,  0.,  0.]), array([ 2.,  1.,  0.,  0.])]

print (move(array, 0))

[array([ 0.,  0.,  2.,  5.]), array([ 0.,  0.,  2.,  3.]), array([ 0.,  0.,  0.,  0.]), array([ 0.,  0.,  1.,  2.])]

print (np.concatenate(list(zip(move(array, 1))), axis=0))

[[ 5.  2.  0.  0.]
 [ 3.  2.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 2.  1.  0.  0.]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM