Sorting a nested list by a certain element without the sorting function.

放肆的年华 提交于 2019-12-02 15:03:04

问题


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.


回答1:


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']]



回答2:


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.




回答3:


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']]


来源:https://stackoverflow.com/questions/43907400/sorting-a-nested-list-by-a-certain-element-without-the-sorting-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!