【问题标题】:Can I trust the order of a dict to remain the same each time it is iterated over?我可以相信每次迭代时字典的顺序都保持不变吗?
【发布时间】:2015-08-27 12:26:33
【问题描述】:

我有以下三个字符串(它们独立存在,但为了方便在这里一起显示):

from mx2.x.org (mx2.x.org. [198.186.238.144])
            by mx.google.com with ESMTPS id g34si6312040qgg.122.2015.04.22.14.49.15
            (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
            Wed, 22 Apr 2015 14:49:16 -0700 (PDT)

from HQPAMAIL08.x.org (10.64.17.33) by HQPAMAIL13.x.x.org
 (10.34.25.11) with Microsoft SMTP Server (TLS) id 14.2.347.0; Wed, 22 Apr
 2015 17:49:13 -0400

from HQPAMAIL13.x.org ([fe80::7844:1f34:e8b2:e526]) by
 HQPAMAIL08.iadb.org ([fe80::20b5:b1cb:9c01:aa86%18]) with mapi id
 14.02.0387.000; Wed, 22 Apr 2015 17:49:12 -0400

我希望根据字符串的反转(从下到上)顺序使用一些值填充 dict。具体来说,对于每个字符串,我将 IP 地址提取为排序索引,然后将完整字符串提取为值。

鉴于顺序很重要,我决定使用列表,最初做了这样的事情(伪代码,上面的一堆文本):

IPs =[]
fullStrings =[]
for string in strings:
    IPs.append[$theIpAddressFoundInTheString]
    fullstrings.append[$theWholeString]

产生以下两个列表(同样,只是一个说明):

IPs ['198.186.238.144', '10.64.17.33', 'fe80::7844:1f34:e8b2:e526']

fullstrings ['from mx2.x.org (mx2.x.org. [198.186.238.144])
                by mx.google.com with ESMTPS id g34si6312040qgg.122.2015.04.22.14.49.15
                (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
                Wed, 22 Apr 2015 14:49:16 -0700 (PDT)', 'from HQPAMAIL08.x.org (10.64.17.33) by HQPAMAIL13.x.x.org
     (10.34.25.11) with Microsoft SMTP Server (TLS) id 14.2.347.0; Wed, 22 Apr
     2015 17:49:13 -0400', 'from HQPAMAIL13.x.org ([fe80::7844:1f34:e8b2:e526]) by
     HQPAMAIL08.x.org ([fe80::20b5:b1cb:9c01:aa86%18]) with mapi id
     14.02.0387.000; Wed, 22 Apr 2015 17:49:12 -0400']

到目前为止,这一直很好,但现在当我开始用这些列表中的值(在硬编码索引处)填充 dict 时,与其他列表中的值进行比较(再次在硬编码索引处)等等,不仅调试变得痛苦,代码也变得不可持续。

我开始使用 dict 重写(返回一个 dict,其中 IP 地址是键,完整的字符串是值)。然后我将执行如下操作:

for k,v in myDictOfIpsAndStrings:
    anotherDict[$someHardcodedText] = k
    anotherDict[$otherHardcodedText] = v        

这是我的担忧:我能确定字典在任何时候被迭代,总是按照字典的创建顺序完成吗?如果不是,那是我唯一的选择恢复到列表(以及繁琐且脆弱的长度比较,这样做固有的分配)等?

我知道,就其本质而言,dict 是未排序的。而且我知道sorted 函数,但我不希望按任何降序/升序等对它们的键进行排序,而是关于维护(以某种方式)创建字典的顺序。

【问题讨论】:

  • 使用collections.OrderedDict!
  • 您的问题不清楚。你希望保持什么样的秩序?您插入元素的顺序?或者当您多次迭代时,您的迭代顺序不会改变?没有保留插入顺序,但是一旦有了字典,顺序就会保持稳定,直到您插入更多键(或删除键)。
  • @minitech 谢谢。文档docs.python.org/2/library/… 包含“2.7 版中的新功能”这一行,但它隐藏在说明的中间。我应该将其视为 OrderedDict 是 2.7 中的新功能,还是只有 popitem() 方法是新的?
  • @Pyderman:OrderedDict 是 2.7 中的新功能。
  • @Pyderman:见Why is the order in Python dictionaries and sets arbitrary?;字典不会保留您创建它或向其添加键的顺序。因此,在 Python 中输入{'foo': 1, 'bar': 2, 'baz': 3} 会得到{'baz': 3, 'bar': 2, 'foo': 1},而对该字典的迭代总是会首先得到'baz',第二个是'bar',第三个是'foo'。直到您插入更多密钥或从中删除密钥。样本中的顺序特定于 2.7,没有散列种子随机化。

标签: python list dictionary iteration


【解决方案1】:

我能确定字典在任何时候被迭代,总是按照字典的创建顺序完成吗?

不,dict 是无序的,并且会按照特定实现决定的方式排列其顺序。

>>> d = {3: 'c', 2: 'b', 1: 'a'}
>>> d
{1: 'a', 2: 'b', 3: 'c'}

看,在我创建 dict 之后,订单立即发生了变化。

如果你想确保你有一个确定的、可控的顺序,你可以使用collections.OrderedDict

>>> from collections import OrderedDict
>>> d = OrderedDict([(3, 'c'), (2, 'b'), (1, 'a')])
>>> d
OrderedDict([(3, 'c'), (2, 'b'), (1, 'a')])

您仍然可以按照您习惯的约定访问OrderedDict

>>> d[3]
'c'
>>> d.get(3)
'c'

请注意,您不必在创建时插入所有元素。如果需要,您可以一次插入一个。

>>> d = OrderedDict()
>>> d[3] = 'c'
>>> d[2] = 'b'
>>> d[1] = 'a'
>>> d[4] = 'd'
>>> d
OrderedDict([(3, 'c'), (2, 'b'), (1, 'a'), (4, 'd')])

【讨论】:

  • 您可能想提及OrderedDict,如果您的解释正确,它将完全适合用例。
【解决方案2】:

您不应该依赖字典的迭代顺序。 唯一您可以获得任何稳定和可重复排序的方法是执行以下操作:

for key in sorted(yourdict):
   more code here

这将为您提供稳定的订单,但可能不是您想要的。

您可能想使用OrderedDict

【讨论】:

  • 可以依赖字典的迭代顺序,前提是您不插入或删除任何内容。您不能依赖的是保留的插入顺序。
  • @MartijnPieters 好的。请参阅我上面的问题。我想如果我想利用这方面的优势,我需要一次性填充字典。
  • @MartijnPieters 谢谢 - 这是很重要的一点。直到现在,我都认为是 dicts 的迭代导致了顺序的变化。
猜你喜欢
  • 2020-03-31
  • 2017-06-04
  • 1970-01-01
  • 2020-11-01
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
相关资源
最近更新 更多