如何在Python中对键为数字字符串的字典排序
我有一个字典:
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 个回答
九年前,我发过一个教程,里面提到
字典是不能排序的——因为它的内容没有顺序!
这个教程展示了如何从字典的键和值中得到排序后的列表。
在今天的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
一般来说,如果你一开始就能更准确地说明你的具体需求,通常能更快得到更好的答案;-)。
在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)
就像大家提到的,字典有自己的顺序,你不能像处理列表那样简单地对它们进行排序。
我想补充一点,如果你只是想按顺序遍历字典里的元素,可以这样做:
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
函数快得多。