问题
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