【问题标题】:sorting dictionary python 3排序字典python 3
【发布时间】:2012-06-18 19:25:44
【问题描述】:

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

这是我的想法:

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

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

【问题讨论】:

  • “无法从这个排序列表中制作字典”是什么意思?字典未按定义排序。如果您想要一个排序字典,请查看Ordered Dictionaries
  • +1 因为我记得遇到过同样的问题(不久前 OrderedDict 甚至还没有正式收藏!)我记得当时的挫败感......

标签: python dictionary


【解决方案1】:

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

TLDR

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

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

比接受的答案快近三倍;包含导入时可能更多。

评论接受的答案

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

如何在 Python 3.7 中按键排序

Python 3.7 最大的变化是the dictionaries are now ordered by default

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

见:

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)}")

【讨论】:

  • 我很惊讶sorted(d.items()) 比带有key 的版本慢。如果所有早期值都相等,元组的排序仅比较第二个和后面的项目(如果第一个值是 dict 键,则永远不会发生)。我想知道为什么这种情况实际上很慢。
  • 你是对的。这可能是由于 cPython 优化,例如github.com/python/cpython/commit/…
【解决方案2】:

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

【讨论】:

  • 我无法创建这样一个 OrderedDict 对象,我输入 OrderedDict={} 但它只是一个名为 OrderedDict 的常规变量..
  • @Jjang, OrderedDict = {} 只是创建了一个名为“OrderedDict”的普通字典。你需要做from collections import OrderedDict,然后用myOrdDic = OrderedDict()之类的东西初始化。
  • 但最终它仍然是一个列表,而不是一个字典......当你打印 OrderedDict 时,它像一个列表一样打印,带有 (),而不是 {} 像字典......
  • 有序字典不一定是排序字典,除非条目以正确的顺序添加到其中。如果之后添加条目,它可能会再次变得未排序。为了保持它的排序,它需要在每次添加时重新创建它,因此使用一个不是实现这种东西的最佳方式。
  • 这是最近过时的:因为 Python 3.7 字典是有序的。请参阅以下答案(以及这篇有趣的帖子softwaremaniacs.org/blog/2020/02/05/dicts-ordered/en
【解决方案3】:

我认为您不需要 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 模块还与其他流行的实现一起维护performance comparison

【讨论】:

  • 对于使用 Anaconda 的用户,现在可以使用 conda install sortedcontainers 进行 conda 安装
【解决方案4】:

Python 的普通dicts 不能以任何特定顺序提供键/元素。为此,您可以使用 collections 模块中的 OrderedDict 类型。请注意,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() 实例的方法效率非常低。

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

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]))) 之类的东西。

【讨论】:

  • +1 表示“不同的数据结构”。 OrderedDict 更像是混合字典/队列;如果您不使用queue 来解决您的问题,OrderedDict 可能也不是正确的解决方案。
  • @senderle,老实说,在我自己的任何工作中,我还没有遇到过适合使用OrderedDict 的情况。这并不是说它不是一个有用的类,但我会说它起着非常小众的作用。
  • 但最终它仍然是一个列表,而不是一个字典...当您打印 OrderedDict 时,它会像一个列表一样打印,带有 (),而不是 {} 像字典...而且我需要最后以dict格式打印
  • @Jjang,它不会保留一个列表,只是 .items() 方法恰好返回一个列表。在内部,OrderedDict 不是列表类型。
  • @Jjang,您没有指定对数据进行排序的目的。我们无法读懂你的想法。如果您只想按顺序打印值,那么只需遍历排序的键列表。我会在一分钟内用一个例子来更新我的帖子。
【解决方案5】:

使用 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')]

【讨论】:

    【解决方案6】:

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

    def order_dic(dic):
        ordered_dic={}
        key_ls=sorted(dic.keys())
        for key in key_ls:
            ordered_dic[key]=dic[key]
        return ordered_dic
    

    【讨论】:

    • 你真的尝试过你的代码吗?我怀疑这根本行不通。您的ordered_dicdic 一样未排序。当您迭代标准dict 时,元素不会按照它们插入的顺序返回。为此,您需要OrderedDict
    【解决方案7】:

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

        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', ... } ]

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

    似乎可行,但我想有更好的解决方案。

    【讨论】:

      【解决方案8】:

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

      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]。我发现这第二个功能几乎没用,但永远无法分辨!

      【讨论】:

      • 嗨法比奥,欢迎来到该网站!这是一个很好的第一个答案。我只是 edited 了一点,以使代码格式正确,但如果您愿意,可以随意进行更多自己的更改。关于您的代码,您可以简化一些事情: 您的第一个循环可以替换为 lista = list(diction.items())items 方法返回一系列键值元组)。您的第二个循环可能是diction2 = dict(lista),因为dict 构造函数接受键值元组序列并从中构建字典。
      • 非常感谢您的回答,感谢您帮助格式化我的评论,最重要的是您的建议。三天前我开始学习如何使用 python 编程,我为我找到的解决这个问题的方法感到特别自豪。当然我知道我只是一个新手,所以再次感谢您的建议。我刚刚意识到我什至可以使用“lista = [(x, diction[x]) for x in diction]”
      【解决方案9】:

      我喜欢 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

      基根

      【讨论】:

      • 对我来说听起来像中文,对不起
      【解决方案10】:

      公认的答案确实有效,但不知何故错过了重要的一点。

      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
      

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

      【讨论】:

        【解决方案11】:

        字典根据定义是无序的,按键排序的主要原因是什么?由 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'}
        

        【讨论】:

          【解决方案12】:

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

          a = {'b':'foo', 'c':'bar', 'e': 'baz'}
          a = {f:a[f] for f in sorted(a, key=a.__getitem__)}
          

          【讨论】:

            猜你喜欢
            • 2013-05-01
            • 1970-01-01
            • 2014-01-23
            • 2018-03-17
            • 1970-01-01
            • 2016-11-19
            • 2011-08-28
            • 2018-05-27
            • 2011-05-18
            相关资源
            最近更新 更多