【问题标题】:Sorting a nested list by a certain element without the sorting function.在没有排序功能的情况下按某个元素对嵌套列表进行排序。
【发布时间】:2017-10-09 23:35:48
【问题描述】:

如果我有这样的嵌套列表:

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

如何在不使用排序或排序功能的情况下根据每个子列表中的最后一个数字将其从高到低排序?

输出:

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

我知道如何做到这一点的唯一方法是使用排序功能,但我想知道如何做到这一点。

【问题讨论】:

  • 为什么不想使用sorted 或sort?
  • 我只是想知道排序列表的不同方式。
  • 我能想到的唯一其他方法就是编写自己的排序函数,这只是作为练习有用。
  • 然后查阅您最喜欢的算法教科书或查看维基百科,了解 QuickSort、MergeSort、InsertionSort 等算法。
  • Python排序已经够快了,为什么要重新发明轮子?

标签: python list sorting nested


【解决方案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']]

【讨论】:

  • 本质上就是SelectionSort(除了SelectionSort可以就地实现)。即使在最好的情况下,它也具有 O(n^2) 复杂度。存在更好的算法。
【解决方案2】:

有很多sorting algorithms可以实现。 Python 的 sorted 内置函数很久以前是 Tim Peters 的 thoughtfully implemented。

但是,这里有另一个使用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']]

通过比较,请注意与sorted 的相似之处,它有几个直观的选项:

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 通常速度很快,但heapq 速度更快。另请参阅this post 了解更多信息。

【讨论】:

    【解决方案3】:

    您可以编写自己的quicksort 函数。您几乎可以切换一些符号来反转输出:

    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)
    

    下一步是确保您提取了正确的数字,并确保您可以将它们映射回父列表,以便您可以再次将它们放到正确的位置 - Allen's answer 有一个很好的方法:

    L = [['James', '1', '2'], ['Alan', '1', '1'], ['Henry', '1', '5']]
    
    keys = [(int(v[-1]),k) for k,v in enumerate(L)] # This line here
    

    该行基本上创建了一个元组列表,用于存储我们想要排序的数字,以及该数字的父列表在总体列表中的索引。所以基本上,对于L,keys = [(2, 0), (1, 1), (5, 2)]。

    因此,您需要更改 quicksort 函数来解决所有这些问题,方法是创建一个可以递归使用的子函数:

    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
    

    然后:

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

    注意:如果最后一个位置有两个具有相同编号的项目,则它们将在原始列表中恢复其原始相对位置(彼此之间)还原 .有关元组比较的更多详细信息,请参阅this answer,并注意我们在此处按 降序 顺序对内容进行排序(否则,它们只会保持彼此之间的原始位置)。所以:

    >>> L = [['Simon', '1', '2'], ['Henry', '1', '5'], ['Finn', '1', '2']
    >>> quicksort(L)
    [['Henry', '1', '5'], ['Finn', '1', '2'], ['Simon', '1', '2']]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-18
      • 1970-01-01
      • 2019-03-23
      • 2016-09-03
      • 2022-01-14
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多