【问题标题】:Python 2.5 dictionary 2 key sortPython 2.5 字典 2 键排序
【发布时间】:2010-09-14 12:27:50
【问题描述】:

我有一个包含 200,000 项的字典(键是字符串,值是整数)。

打印按值降序然后升序键排序的项目的最佳/最 Pythonic 方式是什么(即 2 键排序)?

 a={ 'keyC':1, 'keyB':2, 'keyA':1 }
b = a.items()
b.sort( key=lambda a:a[0])
b.sort( key=lambda a:a[1], reverse=True )
print b
>>>[('keyB', 2), ('keyA', 1), ('keyC', 1)]

【问题讨论】:

  • 查看我对相关问题的回答here

标签: python


【解决方案1】:

您不能对字典进行排序。您必须对项目列表进行排序。

以前的版本是错误的。当你有一个数值时,很容易以相反的顺序排序。这些将做到这一点。但这并不普遍。这只有效,因为该值是数字。

a = { 'key':1, 'another':2, 'key2':1 }

b= a.items()
b.sort( key=lambda a:(-a[1],a[0]) )
print b

这里有一个替代方法,使用显式函数代替 lambda,使用 cmp 代替 key 选项。

def valueKeyCmp( a, b ):
    return cmp( (-a[1], a[0]), (-b[1], b[0] ) )

b.sort( cmp= valueKeyCmp )
print b

更通用的解决方案实际上是两种不同的排序

b.sort( key=lambda a:a[1], reverse=True )
b.sort( key=lambda a:a[0] )
print b

【讨论】:

  • 谢谢,但这并没有解决排序顺序或排序的 2 键性质。
  • 第三个例子不做2键排序,第二个排序撤销第一个
  • @Ricardo Reyes:python 排序是一种稳定的排序。当首先对较小的键进行排序时,得到最终结果。
  • @S.Lott 谢谢。一点.. b.sort(key=lambda a:(-a[1],a[0])) 给我“TypeError:一元的错误操作数类型 -: 'str'”而 b.sort(key=lambda a:(a[1]*-1,a[0]) ) 工作正常。我不明白为什么。
  • @monty:您的值不是数字,而是字符串。检查字典的 repr() 以查看是否有 { 'key':'1' } 。您可能会更高兴 lambda a:(-int(a[1]), a[0]) 强制转换为 int。
【解决方案2】:
data = { 'keyC':1, 'keyB':2, 'keyA':1 }

for key, value in sorted(data.items(), key=lambda x: (-1*x[1], x[0])):
    print key, value

【讨论】:

  • 这是我认为最pythonic的解决方案,也是最容易理解的。
  • 这是按值排序,而不是键。
【解决方案3】:

最pythonic的方法是了解更多关于实际数据的信息——特别是你可以拥有的最大值——然后这样做:

def sortkey((k, v)): 
    return (maxval - v, k)

items = thedict.items()
items.sort(key=sortkey)

但除非您已经知道最大值,否则搜索最大值意味着在字典中循环额外的时间(使用max(thedict.itervalues())),这可能会很昂贵。或者,S.Lott 解决方案的 keyfunc 版本:

def sortkey((k, v)): 
    return (-v, k)

items = thedict.items()
items.sort(key=sortkey)

不关心类型的替代方法是比较函数:

def sortcmp((ak, av), (bk, bv)):
    # compare values 'in reverse'  
    r = cmp(bv, av)
    if not r:
        # and then keys normally
        r = cmp(ak, bk)
    return r

items = thedict.items()
items.sort(cmp=sortcmp) 

并且此解决方案实际上适用于您希望在同一键中混合升序和降序排序的任何类型的键和值。如果您重视简洁,您可以将 sortcmp 编写为:

def sortcmp((ak, av), (bk, bv)):
    return cmp((bk, av), (ak, bv))

【讨论】:

  • 知道最大值是没有用的;使用任何值作为最大值。正如 S.Lott 建议的那样,0 立即浮现在脑海中。 ;)
【解决方案4】:

你可以这样使用:

dic = {'aaa':1, 'aab':3, 'aaf':3, 'aac':2, 'aad':2, 'aae':4}

def sort_compare(a, b):
    c = cmp(dic[b], dic[a])
    if c != 0:
        return c
    return cmp(a, b)

for k in sorted(dic.keys(), cmp=sort_compare):
    print k, dic[k]

但不知道它是多么pythonic :)

【讨论】:

    【解决方案5】:

    以 Thomas Wouters 和 Ricardo Reyes 解决方案为基础:

    def combine(*cmps):
        """Sequence comparisons."""
        def comparator(a, b):
            for cmp in cmps:
                result = cmp(a, b):
                if result:
                    return result
            return 0
        return comparator
    
    def reverse(cmp):
        """Invert a comparison."""
        def comparator(a, b):
            return cmp(b, a)
        return comparator
    
    def compare_nth(cmp, n):
        """Compare the n'th item from two sequences."""
        def comparator(a, b):
            return cmp(a[n], b[n])
        return comparator
    
    rev_val_key_cmp = combine(
            # compare values, decreasing
            reverse(compare_nth(1, cmp)),
    
            # compare keys, increasing
            compare_nth(0, cmp)
        )
    
    data = { 'keyC':1, 'keyB':2, 'keyA':1 }
    
    for key, value in sorted(data.items(), cmp=rev_val_key_cmp):
        print key, value
    

    【讨论】:

      【解决方案6】:
      >>> keys = sorted(a, key=lambda k: (-a[k], k))
      

      >>> keys = sorted(a)
      >>> keys.sort(key=a.get, reverse=True)
      

      然后

      print [(key, a[key]) for key in keys]
      [('keyB', 2), ('keyA', 1), ('keyC', 1)]
      

      【讨论】:

        猜你喜欢
        • 2021-03-28
        • 1970-01-01
        • 2011-01-25
        • 1970-01-01
        • 1970-01-01
        • 2018-08-13
        • 2015-01-04
        • 2013-05-18
        • 2016-07-24
        相关资源
        最近更新 更多