如何在Python中按多个键对对象排序?

发布于 2021-01-29 14:57:57

或者,实际上,如何按多个键对词典列表进行排序?

我有一个字典列表:

b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
 {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
 {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
 {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
 {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
 {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]

并且我需要使用由Total_Points反转的多键排序,然后不由反转TOT_PTS_Misc

可以在命令提示符下完成,如下所示:

a = sorted(b, key=lambda d: (-d['Total_Points'], d['TOT_PTS_Misc']))

但是我必须通过一个函数来运行它,在其中传递列表和排序键。例如,def multikeysort(dict_list, sortkeys):

对于传递给multikeysort函数的任意数量的键,如何使用lambda行将对列表进行排序,并考虑到sortkey可以具有任意数量的键,并且需要识别需要反向排序的键前面加上“-”?

关注者
0
被浏览
95
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    此答案适用于字典中的任何列-否定的列不必是数字。

    def multikeysort(items, columns):
        from operator import itemgetter
        comparers = [((itemgetter(col[1:].strip()), -1) if col.startswith('-') else
                      (itemgetter(col.strip()), 1)) for col in columns]
        def comparer(left, right):
            for fn, mult in comparers:
                result = cmp(fn(left), fn(right))
                if result:
                    return mult * result
            else:
                return 0
        return sorted(items, cmp=comparer)
    

    您可以这样称呼它:

    b = [{u'TOT_PTS_Misc': u'Utley, Alex', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Russo, Brandon', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Chappell, Justin', u'Total_Points': 96.0},
         {u'TOT_PTS_Misc': u'Foster, Toney', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lawson, Roman', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Lempke, Sam', u'Total_Points': 80.0},
         {u'TOT_PTS_Misc': u'Gnezda, Alex', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Kirks, Damien', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Worden, Tom', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Korecz, Mike', u'Total_Points': 78.0},
         {u'TOT_PTS_Misc': u'Swartz, Brian', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Burgess, Randy', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Smugala, Ryan', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Harmon, Gary', u'Total_Points': 66.0},
         {u'TOT_PTS_Misc': u'Blasinsky, Scott', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Carter III, Laymon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Coleman, Johnathan', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Venditti, Nick', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Blackwell, Devon', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Kovach, Alex', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Bolden, Antonio', u'Total_Points': 60.0},
         {u'TOT_PTS_Misc': u'Smith, Ryan', u'Total_Points': 60.0}]
    
    a = multikeysort(b, ['-Total_Points', 'TOT_PTS_Misc'])
    for item in a:
        print item
    

    尝试对任一列取反。您将看到排序顺序相反。

    下一步:对其进行更改,以使其不使用额外的类。


    2016-01-17

    从这个答案中汲取灵感,从满足条件的可迭代项中获取第一项的最佳方法是什么?,我缩短了代码:

    from operator import itemgetter as i
    
    def multikeysort(items, columns):
        comparers = [
            ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
            for col in columns
        ]
        def comparer(left, right):
            comparer_iter = (
                cmp(fn(left), fn(right)) * mult
                for fn, mult in comparers
            )
            return next((result for result in comparer_iter if result), 0)
        return sorted(items, cmp=comparer)
    

    如果您喜欢简洁的代码。


    2016年1月17日晚

    这适用于python3(消除了的cmp参数sort):

    from operator import itemgetter as i
    from functools import cmp_to_key
    
    def cmp(x, y):
        """
        Replacement for built-in function cmp that was removed in Python 3
    
        Compare the two objects x and y and return an integer according to
        the outcome. The return value is negative if x < y, zero if x == y
        and strictly positive if x > y.
    
        https://portingguide.readthedocs.io/en/latest/comparisons.html#the-cmp-function
        """
    
        return (x > y) - (x < y)
    
    def multikeysort(items, columns):
        comparers = [
            ((i(col[1:].strip()), -1) if col.startswith('-') else (i(col.strip()), 1))
            for col in columns
        ]
        def comparer(left, right):
            comparer_iter = (
                cmp(fn(left), fn(right)) * mult
                for fn, mult in comparers
            )
            return next((result for result in comparer_iter if result), 0)
        return sorted(items, key=cmp_to_key(comparer))
    

    受此答案启发,如何在Python 3中自定义排序?



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看