【问题标题】:How to keep keys/values in same order as declared?如何保持键/值与声明的顺序相同?
【发布时间】:2020-08-10 00:08:43
【问题描述】:

我有一本按特定顺序声明的字典,并希望始终保持该顺序。键/值不能真正根据它们的值保持顺序,我只希望它按照我声明的顺序。

如果我有字典:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

如果我查看或遍历它,它的顺序不是这样,有什么方法可以确保 Python 保持我在其中声明键/值的显式顺序?

【问题讨论】:

    标签: python sorting dictionary


    【解决方案1】:

    字典将使用一种可以提高搜索效率的顺序,而您无法更改它,

    您可以只使用一个对象列表(在简单的情况下是一个 2 元素元组,甚至是一个类),并将项目附加到末尾。然后,您可以使用线性搜索来查找其中的项目。

    或者,您可以创建或使用旨在维护秩序的不同数据结构。

    【讨论】:

    • 字典会使用一种让搜索效率更高的顺序终于有人指出了。
    【解决方案2】:

    一般来说,你可以设计一个像字典一样的类,主要是实现__contains____getitem____delitem____setitem__等方法。该类可以具有您喜欢的任何行为,例如在键上提供排序迭代器...

    【讨论】:

      【解决方案3】:

      我在开发 Django 项目时遇到了类似的问题。我无法使用 OrderedDict,因为我运行的是旧版本的 python,所以解决方案是使用 Django 的 SortedDict 类:

      https://code.djangoproject.com/wiki/SortedDict

      例如,

      from django.utils.datastructures import SortedDict
      d2 = SortedDict()
      d2['b'] = 1
      d2['a'] = 2
      d2['c'] = 3
      

      注意:此答案最初来自 2011 年。如果您可以访问 Python 2.7 或更高版本,那么您应该可以访问现在的标准 collections.OrderedDict,其中许多示例已由其他人在此线程中提供。

      【讨论】:

        【解决方案4】:

        请注意,此答案适用于 python3.7 之前的 python 版本。在大多数情况下,CPython 3.6 将插入顺序作为实现细节来维护。从 Python3.7 开始,已声明实现必须保持插入顺序以符合要求。


        python 字典是无序的。如果你想要一个有序的字典,试试collections.OrderedDict

        请注意,OrderedDict 在 python 2.7 中被引入标准库。如果你有旧版本的 python,你可以在ActiveState找到有序字典的食谱。

        【讨论】:

        • 见上面@martijn 的帖子。从 python 3.6 开始,dict 支持插入排序。
        【解决方案5】:
        from collections import OrderedDict
        OrderedDict((word, True) for word in words)
        

        包含

        OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])
        

        如果值为True(或任何其他不可变对象),您也可以使用:

        OrderedDict.fromkeys(words, True)
        

        【讨论】:

        • 当然,值得注意的是,“不可变”部分并不是 Python 将强制执行的硬性规定——它“只是”一个好主意。
        • 请注意,OrderedDict(FUTURE=[], TODAY=[], PAST=[]) 之类的解决方案将无法正常工作,当提到方法时:OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])]) 将保持秩序。
        • @andi 我遇到了另一个问题,当使用 jsonify 时,OrderedDict 在生成 json 数据时似乎失去了它的顺序。无论如何要解决这个问题?
        • github.com/pallets/flask/issues/974这个可以用来解决问题..
        • Python3.7 现在默认有 dict 排序。 mail.python.org/pipermail/python-dev/2017-December/151283.html
        【解决方案6】:

        如果您希望有一个特定顺序的字典,您还可以创建一个列表列表,其中第一项将是键,第二项将是值 看起来像这样 例子

        >>> list =[[1,2],[2,3]]
        >>> for i in list:
        ...     print i[0]
        ...     print i[1]
        
        1
        2
        2
        3
        

        【讨论】:

        • 这不是“字典”,因为如果不搜索整个集合(花费 O(n) 时间),就无法通过键查找项目。
        • 是的,它不是字典,但根据情况,它可以为原发帖者的问题提供有效的解决方案。
        【解决方案7】:

        我在试图弄清楚如何让 OrderedDict 工作时遇到了这篇文章。 PyDev for Eclipse 根本找不到 OrderedDict,所以我最终决定为我的字典键值创建一个元组,因为我希望它们被排序。当我需要输出我的列表时,我只是迭代了元组的值并将迭代的“键”从元组插入到字典中,以按照我需要的顺序检索我的值。

        示例:

        test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
        test_tuple = ( 'val1', 'val2', 'val3', 'val4')
        for key in test_tuple: print(test_dict[key])
        

        这有点麻烦,但我时间紧迫,这是我想出的解决方法。

        注意:其他人建议的列表方法对我来说并不真正有意义,因为列表是有序和索引的(并且也是与字典不同的结构)。

        【讨论】:

        • 很好的解决方案。我将使用它来将 json 写入文件,始终以相同的顺序。
        【解决方案8】:

        不解释理论部分,我举一个简单的例子。

        >>> from collections import OrderedDict
        >>> my_dictionary=OrderedDict()
        >>> my_dictionary['foo']=3
        >>> my_dictionary['aol']=1
        >>> my_dictionary
        OrderedDict([('foo', 3), ('aol', 1)])
        >>> dict(my_dictionary)
        {'foo': 3, 'aol': 1}
        

        【讨论】:

        • 有没有办法像 Dict 类型一样批量分配 OrderedDict?
        • OrderedDict 确实解决了这个问题,但是......在这个特定的例子中,您使用标准字典得到完全相同的结果
        • @Tonechas:我刚刚用标准字典尝试了这个例子,得到了{'aol': 1, 'foo': 3}所以我认为这是一个很好的说明性例子。
        • 每个人都有一个教训:发现(我认为是在 2.4 版本左右)Python 的 predictable hashing might give rise to security vulnerabilities,所以现在不能保证即使是相同代码的两次不同运行也会给出相同的顺序在标准字典中。
        • @tyan 你可以调用 OrderedDict.update() 并使用包含键值对的可迭代对象:d1.upate([(key1, val1), (key2, val2)])
        【解决方案9】:

        你不能用字典做你想做的事。您已经拥有字典 d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}created。我发现一旦它已经创建就没有办法保持秩序了。我所做的是用对象制作一个 json 文件:

        {"ac":33,"gw":20,"ap":102,"za":321,"bs":10}
        

        我用过:

        r = json.load(open('file.json'), object_pairs_hook=OrderedDict)
        

        然后使用:

        print json.dumps(r)
        

        验证。

        【讨论】:

        • 那么为什么不从列表中的 OrderedDict 开始呢? JSON 文件实际上并没有在此处添加任何内容。
        • 是的,列表对于保持秩序更有用,但答案是关于订购字典的问题。只是让人们了解使用字典的局限性,并在他们出于某种原因需要使用字典时为他们提供可能的解决方法。
        【解决方案10】:

        从 Python 3.6 开始,标准的 dict 类型默认保持插入顺序。

        定义

        d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}
        

        将产生一个字典,其中的键按源代码中列出的顺序排列。

        这是通过对稀疏哈希表使用带有整数的简单数组来实现的,其中这些整数索引到另一个存储键值对(加上计算的哈希)的数组中。后一个数组恰好按插入顺序存储项目,整个组合实际上使用的内存比 Python 3.5 和之前使用的实现要少。详情请见original idea post by Raymond Hettinger

        在 3.6 中,这仍被视为实现细节;见What's New in Python 3.6 documentation:

        这个新实现的顺序保留方面被认为是一个实现细节,不应依赖(这可能会在未来发生变化,但希望在更改之前在几个版本中使用该语言的这个新 dict 实现语言规范为所有当前和未来的 Python 实现强制要求保留顺序的语义;这也有助于保持与随机迭代顺序仍然有效的旧版本语言的向后兼容性,例如 Python 3.5。

        Python 3.7 将此实现细节提升为语言规范,因此现在强制dict 在与该版本或更高版本兼容的所有 Python 实现中保持顺序。请参阅pronouncement by the BDFL。从 Python 3.8 开始,字典也支持 iteration in reverse

        在某些情况下,您可能仍想使用collections.OrderedDict() class,因为它在标准dict 类型之上提供了一些附加功能。比如是reversible(这延伸到view objects),并且支持重新排序(通过move_to_end() method)。

        【讨论】:

        • 这个语言规范功能在官方文档中的某处可用吗? (没找到)
        • @ManuelSelva 3.7 what’s new documents mention it(链接到我引用的电子邮件)。 dictionary view objects section 进一步记录了迭代顺序(在iter(dictview) 下:键和值按插入顺序迭代。 并且字典顺序保证为插入顺序。)。
        • @ManuelSelva 数据模型文档的standard type hierarchy section 也涵盖了该主题(字典保留插入顺序,这意味着键将按照它们在字典中按顺序添加的顺序生成。 ).
        • @ManuelSelva 的约定是:除非明确声明某些内容是 CPython 实现细节,否则文档中对标准类型特性的描述使该特性成为语言规范的一部分。
        【解决方案11】:

        你可以做我为字典做的同样的事情。

        创建一个列表和空字典:

        dictionary_items = {}
        fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
        l = fields[0][0]
        m = fields[0][1]
        n = fields[1][0]
        q = fields[1][1]
        dictionary_items[l] = m
        dictionary_items[n] = q
        print dictionary_items
        

        【讨论】:

          【解决方案12】:

          另一种选择是使用 Pandas dataframe,因为它可以保证项目在类似 dict 的结构中的顺序和索引位置。

          【讨论】:

            【解决方案13】:
            from collections import OrderedDict
            list1 = ['k1', 'k2']
            list2 = ['v1', 'v2']
            new_ordered_dict = OrderedDict(zip(list1, list2))
            print new_ordered_dict
            # OrderedDict([('k1', 'v1'), ('k2', 'v2')])
            

            【讨论】:

            • 主要问题不再是字典,而是元组列表
            猜你喜欢
            • 2017-09-21
            • 1970-01-01
            相关资源
            最近更新 更多