Sorting a nested list by a certain element without

2019-03-04 06:59发布

If I have a nested list like this:

L = [['James', '1', '2'], ['Alan', '1', '1'], ['Henry', '1', '5']]

How can I sort it from highest to lowest based on the last number in each of the sub lists without using the sorting or sorted function?

Output:

final = [['Henry', '1', '5'], ['James', '1', '2'], ['Alan', '1', '1']]

The only way I know how to do it is with the sorting function, but I would like to know how to do it without that.

3条回答
The star\"
2楼-- · 2019-03-04 07:36

You can write your own quicksort function. You can pretty much switch some signs to reverse the output:

def quicksort(arr):
    if len(arr) <= 1:
        return arr

    pivot = arr[len(arr)/2]

    left = [x for x in arr if x > pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x < pivot]

    return quicksort(left) + middle + quicksort(right)

The next step would be to make sure you're extracting the proper numbers, and make sure you can map those back to the parent list so you can drop those into the right place again — Allen's answer has a good approach:

L = [['James', '1', '2'], ['Alan', '1', '1'], ['Henry', '1', '5']]

keys = [(int(v[-1]),k) for k,v in enumerate(L)] # This line here

That line basically creates a list of tuples that store the numbers we wanna sort by, and the index of that number's parent list on the overarching list. So basically, for L, keys = [(2, 0), (1, 1), (5, 2)].

So you'd alter the quicksort function to account for all this, by creating a subfunction that can be used recursively:

def quicksort(arr):
    # Put the actual sorting function into a subfunction that can be called recursively
    def subsort(arr2):
        if len(arr2) <= 1:
            return arr2
        pivot = arr2[len(arr2)/2]
        left = [x for x in arr2 if x > pivot]
        middle = [x for x in arr2 if x == pivot]
        right = [x for x in arr2 if x < pivot]
        return subsort(left) + middle + subsort(right)

    # Get the value-key pairs and sort them
    keys = [(int(v[-1]),k) for k,v in enumerate(L)]
    keys = subsort(keys)

    # Do the mapping back to the original array fed into the main function
    final = []
    for i in keys:
        final.append(arr[i[1]])

    return final

And with that:

>>> L = [['James', '1', '2'], ['Alan', '1', '1'], ['Henry', '1', '5']]
>>> quicksort(L)
[['Henry', '1', '5'], ['James', '1', '2'], ['Alan', '1', '1']]

Note: If there are two items with the same number in the last position those are gonna get their original relative position (to one another) in the original list reverted. See this answer for more details on tuple comparison, and note that we're sorting stuff in descending order here (otherwise, they'd just keep their original position relative to one another). So:

>>> L = [['Simon', '1', '2'], ['Henry', '1', '5'], ['Finn', '1', '2']
>>> quicksort(L)
[['Henry', '1', '5'], ['Finn', '1', '2'], ['Simon', '1', '2']]
查看更多
一夜七次
3楼-- · 2019-03-04 07:45

There are many sorting algorithms that can be implemented. Python's sorted builtin was thoughtfully implemented long ago by Tim Peters.

However, here is another sorting option using heapq:

import heapq
import operator as op

heapq.nlargest(len(L), L, key=op.itemgetter(-1))
# [['Henry', '1', '5'], ['James', '1', '2'], ['Alan', '1', '1']]

By comparison, notice the similarity to sorted, which has several intuitive options:

import operator as op

expected = [['Henry', '1', '5'], ['James', '1', '2'], ['Alan', '1', '1']]

r1 = sorted(L, key=op.itemgetter(-1))[::-1]
r2 = sorted(L, key=op.itemgetter(-1), reverse=True)
r3 = list(reversed(sorted(L, key=op.itemgetter(-1))))

assert r1 == r2 == r3 == expected

sorted is generally fast with some exceptions where heapq is faster. See also this post for more information.

查看更多
Deceive 欺骗
4楼-- · 2019-03-04 07:50
L = [['James', '1', '2'], ['Alan', '1', '1'], ['Henry', '1', '5']]

keys = [(int(v[-1]),k) for k,v in enumerate(L)]
final = []

for i in range(len(keys)):
    #find the next biggest element according to last element of the list.
    final.append(L[max(keys)[-1]])
    keys[max(keys)[-1]] = ''

final
Out[83]: [['Henry', '1', '5'], ['James', '1', '2'], ['Alan', '1', '1']]
查看更多
登录 后发表回答