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.
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.]]
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
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.]])