如何在Python中对键为数字字符串的字典排序

11 投票
6 回答
34234 浏览
提问于 2025-04-15 21:03

我有一个字典:

a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }

我想按照键的顺序对这个字典进行排序,排序后应该是这样的:

a = {'1':64,'6':5,'67':7,'88':3, '100':12,'test':34 }

6 个回答

5

九年前,我发过一个教程,里面提到

字典是不能排序的——因为它的内容没有顺序!

这个教程展示了如何从字典的键和值中得到排序后的列表

在今天的Python中,结合你提到的需求,我建议你这样做:

import sys

def asint(s):
    try: return int(s), ''
    except ValueError: return sys.maxint, s

sortedlist = [(k, a[k]) for k in sorted(a, key=asint)]

这里的key=asint是告诉sorted在排序时把那些字符串键当作整数来处理,这样比如'2'就会排在'1''12'之间,而不是排在它们后面——这正是你需要的,同时所有只包含数字的键会排在所有非数字键的前面。如果你还需要处理那些表示大于系统最大整数的全数字键字符串,那就稍微复杂一点,但还是可以做到的:

class Infinity(object):
    def __cmp__(self, other): return 0 if self is other else 1
infinite = Infinity()
def asint(s):
    try: return int(s), ''
    except ValueError: return infinite, s

一般来说,如果你一开始就能更准确地说明你的具体需求,通常能更快得到更好的答案;-)。

7

在Python中,你不能对一个dict(字典)进行排序,因为字典本身是没有顺序的。你可以在使用字典里的内容之前,先用sorted()这个内置函数对它的项进行排序。为了区分数字键和字符串键,你还需要一个辅助函数:

def get_key(key):
    try:
        return int(key)
    except ValueError:
        return key
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
print sorted(a.items(), key=lambda t: get_key(t[0]))

不过在Python 3.1(和2.7)中,collections模块里有一个叫做collections.OrderedDict的类型,可以用来实现你想要的效果,像下面这样:

def get_key(key):
    try:
        return int(key)
    except ValueError:
        return key
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
b = collections.OrderedDict(sorted(a.items(), key=lambda t: get_key(t[0])))
print(b)
15

就像大家提到的,字典有自己的顺序,你不能像处理列表那样简单地对它们进行排序。

我想补充一点,如果你只是想按顺序遍历字典里的元素,可以这样做:

for k in sorted(a):
    print k, a[k] # or whatever.

如果你更喜欢使用列表推导式(根据Alex的说法):

sortedlist = [(k, a[k]) for k in sorted(a)]

我想指出,Alex使用的 key=int 在你的例子中是行不通的,因为你的一个键是 'test'。如果你真的想让数字排在非数字前面,你需要传入一个 cmp 函数:

def _compare_keys(x, y):
    try:
        x = int(x)
    except ValueError:
        xint = False
    else:
        xint = True
    try:
        y = int(y)
    except ValueError:
        if xint:
            return -1
        return cmp(x.lower(), y.lower())
        # or cmp(x, y) if you want case sensitivity.
    else:
        if xint:
            return cmp(x, y)
        return 1

for k in sorted(a, cmp=_compare_keys):
    print k, a[k] # or whatever.

或者也许你对你的键了解得足够多,可以写一个函数,把它们转换成一个能正确排序的字符串(或其他对象):

# Won't work for integers with more than this many digits, or negative integers.
MAX_DIGITS = 10
def _keyify(x):
    try:
        xi = int(x)
    except ValueError:
        return 'S{0}'.format(x)
    else:
        return 'I{0:0{1}}'.format(xi, MAX_DIGITS)

for k in sorted(a, key=_keyify):
    print k, a[k] # or whatever.

这样做会比使用 cmp 函数快得多。

撰写回答