49

我正在研究 python 3.2.2。打破我的头脑超过 3 个小时来按它的键对字典进行排序。我设法使它成为一个带有 2 个参数成员的排序列表,但最终不能使它成为一个排序字典。

这就是我的想法:

myDic={10: 'b', 3:'a', 5:'c'}
sorted_list=sorted(myDic.items(), key=lambda x: x[0])

但无论如何我都无法从这个排序列表中制作字典。我怎么做?谢谢!

4

12 回答 12

57

适用于 Python 3.7 的现代且快速的解决方案。也可以在 Python 3.6 的一些解释器中工作。

TLDR

要按键对字典进行排序,请使用:

sorted_dict = {k: disordered[k] for k in sorted(disordered)}

几乎比公认的答案快三倍;当你包括进口时,可能更多。

评论接受的答案

接受的答案中的示例而不是仅迭代键 - 使用key参数 ofsorted()或 dict 迭代的默认行为 - 迭代元组(key, value),令人惊讶的是,这比仅比较键和访问列表理解中的字典元素要慢得多.

如何在 Python 3.7 中按键排序

Python 3.7 最大的变化是字典现在是默认排序的

  • 您可以使用字典推导生成排序字典。
  • OrderedDict出于兼容性考虑,使用可能仍然是可取的。
  • 不要使用sorted(d.items())没有key

看:

disordered = {10: 'b', 3: 'a', 5: 'c'}

# sort keys, then get values from original - fast
sorted_dict = {k: disordered[k] for k in sorted(disordered)}

# key = itemgetter - slower
from operator import itemgetter
key = itemgetter(0)
sorted_dict = {k: v for k, v in sorted(disordered.items(), key=key)}

# key = lambda - the slowest
key = lambda item: item[0]
sorted_dict = {k: v for k in sorted(disordered.items(), key=key)} 

计时结果

Best for {k: d[k] for k in sorted(d)}: 7.507327548999456
Best for {k: v for k, v in sorted(d.items(), key=key_getter)}: 12.031082626002899
Best for {k: v for k, v in sorted(d.items(), key=key_lambda)}: 14.22885995300021

Best for dict(sorted(d.items(), key=key_getter)): 11.209122000000207
Best for dict(sorted(d.items(), key=key_lambda)): 13.289728325995384
Best for dict(sorted(d.items())): 14.231471302999125

Best for OrderedDict(sorted(d.items(), key=key_getter)): 16.609151654003654
Best for OrderedDict(sorted(d.items(), key=key_lambda)): 18.52622927199991
Best for OrderedDict(sorted(d.items())): 19.436101284998585

测试代码:

from timeit import repeat

setup_code = """
from operator import itemgetter
from collections import OrderedDict
import random
random.seed(0)
d = {i: chr(i) for i in [random.randint(0, 120) for repeat in range(120)]}
key_getter = itemgetter(0)
key_lambda = lambda item: item[0]
"""

cases = [
    # fast
    '{k: d[k] for k in sorted(d)}',
    '{k: v for k, v in sorted(d.items(), key=key_getter)}',
    '{k: v for k, v in sorted(d.items(), key=key_lambda)}',
    # slower
    'dict(sorted(d.items(), key=key_getter))',
    'dict(sorted(d.items(), key=key_lambda))',
    'dict(sorted(d.items()))',
    # the slowest 
    'OrderedDict(sorted(d.items(), key=key_getter))',
    'OrderedDict(sorted(d.items(), key=key_lambda))',
    'OrderedDict(sorted(d.items()))',
]

for code in cases:
    times = repeat(code, setup=setup_code, repeat=3)
    print(f"Best for {code}: {min(times)}")
于 2018-03-06T16:43:20.080 回答
50

dict不保持其元素的顺序。您需要的是 OrderedDict:http ://docs.python.org/library/collections.html#collections.OrderedDict

编辑

使用示例:

>>> from collections import OrderedDict
>>> a = {'foo': 1, 'bar': 2}
>>> a
{'foo': 1, 'bar': 2}
>>> b = OrderedDict(sorted(a.items()))
>>> b
OrderedDict([('bar', 2), ('foo', 1)])
>>> b['foo']
1
>>> b['bar']
2
于 2012-06-18T19:29:58.617 回答
18

我不认为你想要一个 OrderedDict。听起来您更喜欢SortedDict,这是一个按排序顺序维护其键的字典。sortedcontainers模块就提供了这样一种数据类型它是用纯 Python 编写的,速度与 C 一样快,具有 100% 的覆盖率和数小时的压力。

使用 pip 安装很容易:

pip install sortedcontainers

请注意,如果您不能,pip install那么您可以简单地从开源存储库中提取源文件。

然后你的代码很简单:

from sortedcontainers import SortedDict
myDic = SortedDict({10: 'b', 3:'a', 5:'c'})
sorted_list = list(myDic.keys())

sortedcontainers 模块还保持与其他流行实现的性能比较。

于 2014-09-23T06:41:28.630 回答
11

Python 的普通dicts程序不能以任何特定顺序提供键/元素。为此,您可以使用模块中的OrderedDict类型collections。请注意,该OrderedDict类型仅保留插入顺序的记录。如果您希望后续视图/迭代器每次都按顺序返回元素,则必须在初始化字典之前对条目进行排序。例如:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sorted_list=sorted(myDic.items(), key=lambda x: x[0])
>>> myOrdDic = OrderedDict(sorted_list)
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b')]
>>> myOrdDic[7] = 'd'
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b'), (7, 'd')]

如果您想为新添加的项目保持正确的顺序,您确实需要使用不同的数据结构,例如二叉树/堆。除非您的数据完全是静态的,否则这种构建排序列表并使用它来初始化新OrderedDict()实例的方法效率非常低。

编辑:因此,如果对数据进行排序的对象只是按顺序打印它,以类似于 pythondict对象的格式,类似以下内容就足够了:

def pprint_dict(d):
    strings = []
    for k in sorted(d.iterkeys()):
        strings.append("%d: '%s'" % (k, d[k]))
    return '{' + ', '.join(strings) + '}'

请注意,此函数在键、值对的类型方面不灵活(即,它希望键是整数,对应的值是字符串)。如果您需要更大的灵活性,请改用类似的东西strings.append("%s: %s" % (repr(k), repr(d[k])))

于 2012-06-18T19:30:18.087 回答
3

使用 Python 3.7,我可以这样做:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(dict(sortDic))
{3:'a', 5:'c', 10: 'b'}

如果你想要一个元组列表:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(sortDic)
[(3, 'a'), (5, 'c'), (10, 'b')]
于 2018-08-23T10:33:24.227 回答
1

也许不是那么好,但我已经想到了这一点:

def order_dic(dic):
    ordered_dic={}
    key_ls=sorted(dic.keys())
    for key in key_ls:
        ordered_dic[key]=dic[key]
    return ordered_dic
于 2015-05-26T14:47:48.800 回答
1

这个问题的任何现代解决方案?我解决了这个问题:

    order = sorted([ job['priority'] for job in self.joblist ])
    sorted_joblist = []
    while order:
        min_priority = min(order)
        for job in self.joblist:
            if job['priority'] == min_priority:
                sorted_joblist += [ job ]
                order.remove(min_priority)
    self.joblist = sorted_joblist

作业列表的格式为: joblist = [ { 'priority' : 3, 'name' : 'foo', ... }, { 'priority' : 1, 'name' : 'bar', ... } ]

  • 基本上我创建了一个列表(顺序),其中包含我想要对字典进行排序的所有元素
  • 然后我迭代这个列表和字典,当我在字典上找到项目时,我将它发送到一个新的字典并从“订单”中删除该项目。

似乎正在工作,但我想有更好的解决方案。

于 2016-11-26T07:27:34.040 回答
1

我不确定这是否有帮助,但我有一个类似的问题,我设法通过定义一个合适的函数来解决它:

def sor_dic_key(diction):
    lista = []
    diction2 = {}
    for x in diction:
        lista.append([x, diction[x]])
    lista.sort(key=lambda x: x[0])
    for l in lista:
        diction2[l[0]] = l[1]
    return diction2

此函数返回另一个具有相同键和相对值的字典,但按其键排序。同样,我定义了一个函数,可以按字典的值对字典进行排序。我只需要在 lambda 函数中使用x[1]而不是。x[0]我发现这第二个功能几乎没用,但永远无法分辨!

于 2020-04-04T02:49:39.913 回答
0

我喜欢这种东西的python numpy!例如:

r=readData()
nsorted = np.lexsort((r.calls, r.slow_requests, r.very_slow_requests, r.stalled_requests))

我有一个将 CSV 数据导入 numpy 并按列优先级排序的示例。 https://github.com/unixunion/toolbox/blob/master/python/csv-numpy.py

基根

于 2012-06-18T19:52:22.720 回答
0

字典根据定义是无序的,按键排序的主要原因是什么?由 sort 方法创建的元组列表可用于任何需要,但将元组列表更改回字典将返回随机顺序

>>> myDic
{10: 'b', 3: 'a', 5: 'c'}
>>> sorted(myDic.items())
[(3, 'a'), (5, 'c'), (10, 'b')]
>>> print(dict(myDic.items()))
{10: 'b', 3: 'a', 5: 'c'}
于 2019-04-13T17:47:23.233 回答
0

接受的答案肯定有效,但不知何故错过了重要的一点。

OP 要求按其排序的字典,这keys实际上是不可能的,而不是OrderedDict在做什么。

OrderedDict 以插入顺序维护字典的内容。插入的第一个项目,插入的第二个项目,等等。

>>> d = OrderedDict()
>>> d['foo'] = 1
>>> d['bar'] = 2
>>> d
OrderedDict([('foo', 1), ('bar', 2)])

>>> d = OrderedDict()
>>> d['bar'] = 2
>>> d['foo'] = 1
>>> d
OrderedDict([('bar', 2), ('foo', 1)])

因此,我将无法真正对字典进行就地排序,而只是创建一个插入顺序与键顺序匹配的新字典。这在新字典为 b 的已接受答案中是明确的。

如果您通过容器保持对字典的访问,这可能很重要。如果您以后打算通过添加或删除项目来更改字典,这也很重要:它们不会按键顺序插入,而是在字典的末尾。

>>> d = OrderedDict({'foo': 5, 'bar': 8})
>>> d
OrderedDict([('foo', 5), ('bar', 8)])
>>> d['alpha'] = 2
>>> d
OrderedDict([('foo', 5), ('bar', 8), ('alpha', 2)])

现在,字典按其键排序是什么意思?这在通过键访问元素时没有区别,这仅在您迭代项目时才重要。将其作为字典本身的属性似乎有点矫枉过正。在许多情况下,迭代时对 keys() 进行排序就足够了。

这意味着它等同于:

>>> d = {'foo': 5, 'bar': 8}
>>> for k,v in d.iteritems(): print k, v

在按键字典排序的假设上或:

>>> d = {'foo': 5, 'bar': 8}
>>> for k, v in iter((k, d[k]) for k in sorted(d.keys())): print k, v

当然,通过重载迭代器和维护排序的键列表将这种行为包装在对象中并不难。但这很可能是矫枉过正。

于 2018-04-27T10:42:38.623 回答
0

使用推导按值对字典进行排序。我认为它就像 1 行一样好,不需要函数或 lambdas

a = {'b':'foo', 'c':'bar', 'e': 'baz'}
a = {f:a[f] for f in sorted(a, key=a.__getitem__)}
于 2019-12-14T17:26:22.710 回答