简体   繁体   中英

python: Sorting a list of lists over a range of elements

I am trying now for days to fix this, but I just can't get anywhere with this problem.

I have a list of lists, where each list consists of values from 0 to 5:

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

Now I would like to sort this list starting with the very last element, then the second last etc. all the way to the beginning, to get something like:

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

All replies to sorting arrays/lists questions that I found online dealt with distinct columns/elements, whereas I couldn't get this range of elements to work. In the end the only solution that worked was:

array = array[np.lexsort((array[:,-9], array[:,-8], array[:,-7], array[:,-6], array[:,-5], array[:,-4], array[:,-3], array[:,-2], array[:,-1]))]

This is not only very ugly, but also not very flexible. Any attempt to replace this command with a loop or a variable failed miserably.

Any suggestions would be very much appreciated!

Given:

LoL=[[ 0.,  0.,  4.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,],
 [ 0.,  0.,  1.,  2.,  3.,  3.,  3.,  3.,  3.,  3.,],
 [ 0.,  0.,  2.,  3.,  4.,  4.,  1.,  2.,  1.,  2.,],
 [ 0.,  0.,  3.,  4.,  5.,  1.,  4.,  4.,  5.,  5.,],
 [ 0.,  0.,  5.,  3.,  3.,  3.,  4.,  3.,  4.,  3.,],
 [ 0.,  0.,  3.,  4.,  1.,  1.,  1.,  1.,  4.,  4.,],
 [ 0.,  0.,  3.,  4.,  1.,  3.,  3.,  3.,  3.,  1.,],
 [ 0.,  0.,  1.,  4.,  4.,  5.,  3.,  4.,  3.,  1.,]]

Use a key function:

>>> sorted(LoL, key=lambda l: l[::-1])
[[0.0, 0.0, 3.0, 4.0, 1.0, 3.0, 3.0, 3.0, 3.0, 1.0], 
 [0.0, 0.0, 1.0, 4.0, 4.0, 5.0, 3.0, 4.0, 3.0, 1.0], 
 [0.0, 0.0, 2.0, 3.0, 4.0, 4.0, 1.0, 2.0, 1.0, 2.0], 
 [0.0, 0.0, 4.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0], 
 [0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0], 
 [0.0, 0.0, 5.0, 3.0, 3.0, 3.0, 4.0, 3.0, 4.0, 3.0], 
 [0.0, 0.0, 3.0, 4.0, 1.0, 1.0, 1.0, 1.0, 4.0, 4.0], 
 [0.0, 0.0, 3.0, 4.0, 5.0, 1.0, 4.0, 4.0, 5.0, 5.0]]

If those are numpy arrays, use ndarray.sort:

>>> m=np.matrix(LoL)
>>> m
array([[ 0.,  0.,  4.,  2.,  2.,  2.,  2.,  2.,  2.,  2.],
       [ 0.,  0.,  1.,  2.,  3.,  3.,  3.,  3.,  3.,  3.],
       [ 0.,  0.,  2.,  3.,  4.,  4.,  1.,  2.,  1.,  2.],
       [ 0.,  0.,  3.,  4.,  5.,  1.,  4.,  4.,  5.,  5.],
       [ 0.,  0.,  5.,  3.,  3.,  3.,  4.,  3.,  4.,  3.],
       [ 0.,  0.,  3.,  4.,  1.,  1.,  1.,  1.,  4.,  4.],
       [ 0.,  0.,  3.,  4.,  1.,  3.,  3.,  3.,  3.,  1.],
       [ 0.,  0.,  1.,  4.,  4.,  5.,  3.,  4.,  3.,  1.]])
>>> m[m[:,-1].argsort()]
array([[ 0.,  0.,  3.,  4.,  1.,  3.,  3.,  3.,  3.,  1.],
       [ 0.,  0.,  1.,  4.,  4.,  5.,  3.,  4.,  3.,  1.],
       [ 0.,  0.,  4.,  2.,  2.,  2.,  2.,  2.,  2.,  2.],
       [ 0.,  0.,  2.,  3.,  4.,  4.,  1.,  2.,  1.,  2.],
       [ 0.,  0.,  1.,  2.,  3.,  3.,  3.,  3.,  3.,  3.],
       [ 0.,  0.,  5.,  3.,  3.,  3.,  4.,  3.,  4.,  3.],
       [ 0.,  0.,  3.,  4.,  1.,  1.,  1.,  1.,  4.,  4.],
       [ 0.,  0.,  3.,  4.,  5.,  1.,  4.,  4.,  5.,  5.]])

You can simply transpose the input array and then use np.lexsort to get the sorting indices for a vectorized and thus pretty efficient solution, like so -

array[np.lexsort(array[:,1:].T)]

Sample run -

In [128]: # Random array of integers
     ...: array = np.random.randint(0,9,(5,10))
     ...: 
     ...: # Original method
     ...: A = ((array[:,-9], array[:,-8], array[:,-7], array[:,-6], array[:,-5], \
     ...:       array[:,-4], array[:,-3], array[:,-2], array[:,-1]))
     ...: out_loopy = array[np.lexsort(A)]
     ...: 
     ...: # Vectorized method
     ...: out_vectorized = array[np.lexsort(array[:,1:].T)]
     ...: 

In [129]: np.allclose(out_loopy,out_vectorized)
Out[129]: True

Use the following sorting function

def mysort(list1,list2):
  i = min(len(list1),len(list2))-1  # in case unequal lines
  while (i>0) and list1[i]== list2[i]:
    i -= 1
  return cmp(list1[i],list2[i])

Tested with (it prints the right answer)

LL = [[ 0,  0,  4,  2,  2,  2,  2,  2,  2,  2,],
 [ 0,  0,  1,  2,  3,  3,  3,  3,  3,  3,],
 [ 0,  0,  2,  3,  4,  4,  1,  2,  1,  2,],
 [ 0,  0,  3,  4,  5,  1,  4,  4,  5,  5,],
 [ 0,  0,  5,  3,  3,  3,  4,  3,  4,  3,],
 [ 0,  0,  3,  4,  1,  1,  1,  1,  4,  4,],
 [ 0,  0,  3,  4,  1,  3,  3,  3,  3,  1,],
 [ 0,  0,  1,  4,  4,  5,  3,  4,  3,  1,]]

LL.sort(mysort)
print (LL)

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