Python 2.5字典2键排序

时间:2020-03-06 14:58:27  来源:igfitidea点击:

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

打印按降序然后升序排序(即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)]

解决方案

我们无法对字典进行排序。我们必须对项目列表进行排序。

以前的版本是错误的。当我们有一个数值时,很容易按相反的顺序排序。这些将做到这一点。但这不是一般性的。这仅起作用,因为该值为数字。

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

最有效的方法是对实际数据有更多了解-具体来说,就是我们可以拥有的最大值-然后执行以下操作:

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

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

但是,除非我们已经知道最大值,否则搜索最大值意味着在dict上循环额外的时间(使用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))

我们可以使用如下所示的内容:

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 :)

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

基于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

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