简体   繁体   English

如何在 Python 中对具有键作为数字字符串的字典进行排序

[英]How to sort a dictionary having keys as a string of numbers in Python

I have a dictionary:我有一本字典:

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

I want to sort this dictionary with respect to key so it looks like:我想根据键对这本字典进行排序,因此它看起来像:

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

Like everyone else has pointed out, dictionaries have their own ordering and you can't just sort them like you would a list.就像其他人指出的那样,字典有自己的排序方式,您不能像对列表一样对它们进行排序。

One thing I would like to add is that, if you just want to go through the elements of a dictionary in sorted order, that's just:我想补充的一件事是,如果您只想按排序顺序浏览字典的元素,那就是:

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

If you'd rather have a list comprehension (per Alex):如果你更喜欢列表理解(按亚历克斯):

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

I would like to point out that Alex's use of key=int won't work with your example because one of your keys is 'test' .我想指出 Alex 对key=int的使用不适用于您的示例,因为您的一个键是'test' If you really want he numbers sorted before the non-numerics, you'll have to pass in a cmp function:如果您真的希望在非数字之前对数字进行排序,则必须传入一个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.

Or maybe you know enough about your keys to write a function to convert them into a string (or other object) that sorts right:或者你可能对你的键有足够的了解来编写一个函数来将它们转换成一个正确排序的字符串(或其他对象):

# 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.

This would be much faster than using a cmp function.这将比使用cmp函数快得多。

You cannot sort a dict in Python as the dict type is inherently unordered.您不能对一个dict作为在Python dict类型本质上是无序的。 What you can do is sort the items before you used them using the sorted() built in function.您可以做的是在使用sorted()内置函数之前对项目进行sorted() You will also need a helper function to distinguish between your numerical and string keys:您还需要一个辅助函数来区分数字键和字符串键:

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

However in Python 3.1 (and 2.7) the collections module contains the collections.OrderedDict type that can be used to achieve the effect you want like below:但是在 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)

9 years ago I posted arecipe that starts 9 年前我发布了一个开始食谱

Dictionaries can't be sorted -- a mapping has no ordering!字典无法排序——映射没有排序!

and shows how to get sorted lists out of a dict's keys and values.并展示了如何从字典的键和值中获取排序列表

With today's Python, and your expressed-plus-implied specs, I'd suggest:使用今天的 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)]

the key=asint is what tells sorted to treat those string keys as integers for sorting purposes, so that eg '2' sorts between '1' and '12' , rather than after them both -- that's what you appear to require, as well as having all non-all-digits keys sort after all all-digits ones. key=asint告诉sorted将这些字符串键视为整数以进行排序,以便例如'2''1''12'之间排序,而不是在它们之后排序 - 这就是您似乎需要的以及让所有非全数字键在所有全数字键之后排序。 If you need to also deal with all-digits key strings that express integers larger than sys.maxint, it's a bit trickier, but still doable:如果您还需要处理表示大于 sys.maxint 的整数的全数字键字符串,这有点棘手,但仍然可行:

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

In general, you can get better answers faster if you specify your exact requirements more precisely from the start;-).一般来说,如果您从一开始就更准确地指定您的确切要求,您可以更快地获得更好的答案;-)。

Dictionaries are unordered.字典是无序的。 You cannot sort one like you show because the resultant a is a dict, and dicts do not have order.你不能像你展示的那样排序,因为结果a是一个 dict,而 dicts 没有顺序。

If you want, say, a list a list of the keys in sorted order, you can use code like如果你想要一个按排序顺序列出的键列表,你可以使用像这样的代码

>>> def my_key(dict_key):
...     try:
...         return int(dict_key)
...     except ValueError:
...         return dict_key
...
>>> sorted(a, key=my_key)
['1', '6', '67', '88', '100', 'test']

This relies on the stupid Python behavior that instances of str are always greater than instances of int .这依赖于愚蠢的 Python 行为,即str实例总是大于int实例。 (The behaviour is fixed in Python 3.) In an optimal design, the keys of your dict would be things you could compare sanely and you wouldn't mix in strings representing numbers with strings representing words. (该行为在 Python 3 中是固定的。)在最佳设计中,您的 dict 的键将是您可以合理比较的东西,并且您不会将表示数字的字符串与表示单词的字符串混合在一起。

If you want to keep the keys in always-sorted order, you can use the bisect module or implement a mapping that relies on a tree data structure.如果要保持键始终按顺序排序,可以使用bisect模块或实现依赖于树数据结构的映射。 The bisect module does not accept a key argument like the sorting stuff because this would be potentially inefficient; bisect模块不接受像排序一样的key参数,因为这可能效率低下; you would use the decorate–use–undecorate pattern if you chose to use bisect , keeping a sorted list that depends on the result of the key function.如果您选择使用bisect ,您将使用decorate-use-undecorate 模式,保留一个取决于键函数结果的排序列表。

If you install my blist package, it includes a sorteddict type.如果你安装了我的blist包,它包含一个sorteddict类型。 Then you could simply:那么你可以简单地:

from blist import sorteddict

def my_key(dict_key):
       try:
              return int(dict_key)
       except ValueError:
              return dict_key

a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 }
print sorteddict(my_key, **a).keys()

Output:输出:

['1', '6', '67', '88', '100', 'test']

what you could do is also the following:您还可以做以下事情:

sorted_keys = sorted(list(a.keys()), key = lambda x: (len(x),x))
sorted_dict = {k:a[k] for k in sorted_keys}

The most important part is key = lambda x: (len(x),x) which I took from here最重要的部分是key = lambda x: (len(x),x)我从这里获取

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM