Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort array in Python without modifying specific element positions

I have a numpy array in Python which is n-by-n (in the example is 3-by-3)and contains zero values in all the diagonal positions. e.g

array([[ 0.   , -0.65  ,  1.3 ,   0.56],
       [ 0.45 ,  0.    ,  0.54,   43   ],
       [ 0.5  ,  0.12  ,  0.  ,   7    ]
       [ 0.2  ,  0.3  ,  0.4  ,   0    ]])

Is it possible to sort the array without modifying the diagonal positions so as to look like the one below? Because all of the sorting functions will take into account the "zeros" that exist in the diagonal positions and will change their relative position.

array([[ 0.   , 1.3    ,  0.56  ,   -0.65],
       [ 43   ,  0.    ,  0.54  ,   0.45   ],
       [ 7    ,  0.5   ,  0.    ,   0.12    ]
       [ 0.4  ,  0.3  ,  0.2    ,   0    ]])

If the above operation cannot be done, then the N maximum values and their corresponding indexes in each row could suffice.

Till now i have tried sort and argsort but with no result.

like image 373
Giorgos Lazaridis Avatar asked Oct 20 '22 16:10

Giorgos Lazaridis


2 Answers

I'm a little late to this question, but if you're looking for a NumPy-only solution, you could substitute inf for your diagonal, sort in your chosen order, and then shuffle the inf column back to the diagonal:

In [189]: a = np.array([[ 0.   , -0.65  ,  1.3 ,   0.56],
   .....:        [ 0.45 ,  0.    ,  0.54,   43   ],
   .....:        [ 0.5  ,  0.12  ,  0.  ,   7    ],
   .....:        [ 0.2  ,  0.3  ,  0.4  ,   0    ]])

In [190]: np.fill_diagonal(a,np.inf)

In [191]: a.sort()

In [192]: a = a[:,::-1]

In [193]: for i in range(1,len(a)):
   .....:         a[i,:i+1] = np.roll(a[i,:i+1], i)
   .....:     

In [194]: np.fill_diagonal(a, 0)

In [195]: a
Out[195]: 
array([[  0.  ,   1.3 ,   0.56,  -0.65],
   [ 43.  ,   0.  ,   0.54,   0.45],
   [  7.  ,   0.5 ,   0.  ,   0.12],
   [  0.4 ,   0.3 ,   0.2 ,   0.  ]])
like image 86
xnx Avatar answered Oct 22 '22 07:10

xnx


The easiest approach is to remove the zeroes, sort, then add the zeroes back along the diagonal:

>>> a = [[0,1,2],[3,0,0],[5,6,0]]
>>> no_zeroes = [r[:i] + r[i+1:] for i, r in enumerate(a)]
>>> no_zeroes
[[1, 2], [3, 0], [5, 6]]
>>> sorted_no_zeroes = [sorted(r, reverse=True) for r in no_zeroes]
>>> sorted_no_zeroes
[[2, 1], [3, 0], [6, 5]]
>>> sorted_with_zeroes = [r[:i] + [0] + r[i:] for i, r in enumerate(sorted_no_zeroes)]
>>> sorted_with_zeroes
[[0, 2, 1], [3, 0, 0], [6, 5, 0]]

Wrapped into a function:

>>> def sort_ignoring_zeroes(a):
...  s = [sorted(r[:i] + r[i+1:], reverse=True) for i, r in enumerate(a)]
...  return [r[:i] + [0] + r[i:] for i, r in enumerate(s)]
...
>>> sort_ignoring_zeroes(
          [[ 0.   , 1.3    ,  0.56  ,   -0.65],
...        [ 43   ,  0.    ,  0.54  ,   0.45],
...        [ 7    ,  0.5   ,  0.    ,   0.12]])
[[0, 1.3, 0.56, -0.65],
 [43, 0, 0.54, 0.45],
 [7, 0.5, 0, 0.12]]
>>>
like image 33
kevingessner Avatar answered Oct 22 '22 08:10

kevingessner