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

前端 未结 3 578
囚心锁ツ
囚心锁ツ 2021-01-18 20:19

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.         


        
相关标签:
3条回答
  • 2021-01-18 20:58
    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.]]
    
    0 讨论(0)
  • 2021-01-18 21:02

    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

    0 讨论(0)
  • 2021-01-18 21:07

    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.]])
    
    0 讨论(0)
提交回复
热议问题