在Python中,如何按已排序的键顺序遍历字典?


211

有一个现有功能以以下结尾,其中d是一个字典:

return d.iteritems()

返回给定字典的未排序迭代器。我想返回一个遍历按key排序的项目的迭代器。我怎么做?

Answers:


171

尚未对此进行广泛的测试,但是可以在Python 2.5.2中使用。

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

如果您习惯于使用for key, value in d.iteritems(): ...迭代器而不是迭代器,那么上述方法仍然可以使用

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

在Python 3.x中,使用d.items()代替d.iteritems()返回迭代器。


29
如@Claudiu所述,请使用.items()而不是iteritems():iteritems不适用于Python 3.x,但items()可从Python 2.6获得。
雷米

40
这并不明显。实际上,items()创建列表并因此使用内存,而iteritems()实际上不使用内存。使用什么主要取决于字典的大小。此外,从Python 2到Python 3的自动转换工具(2to3)会自动处理从iteritems()到的转换items(),因此无需担心。
Eric O Lebigot

5
@HowerHell使用a collections.OrderedDict然后进行一次排序并始终按排序顺序获得项目。
Mark Harviston

9
但是@EOL,即使iteritems()不使用内存,也必须将所有内容都放入for的内存中sorted(),因此使用items()iteritems()这里在内存方面没有区别。
理查德(Richard)

8
@Richard:虽然确实必须将所有元素都拉到内存中,但它们使用两次存储items()(在,返回的列表中items(),在排序列表中),使用一次存储iteritems()(仅在排序列表中)。
Eric O Lebigot

83

使用 sorted()功能:

return sorted(dict.iteritems())

如果您想在排序结果上使用实际的迭代器,由于sorted()返回列表,请使用:

return iter(sorted(dict.iteritems()))

我失败了:<type'exceptions.TypeError'>:iter()返回了'list'类型的非迭代器
Mike

这可能是因为您使用“ dict”作为变量名。“ dict”实际上是词典的类型名称。只需在此处使用其他名称,例如“ mydict”,瞧。
utku_karatas

1
还是行不通。您是否肯定sorted()返回了另一个迭代器,而不是常规列表?
迈克,

此异常何时何地发生?您可以毫无问题地遍历列表

1
同意,跳。除了跳过文件中的行时,我认为我从未直接调用.next()。我们的iter(sorted(dict.iteritems()))解决方案最终还是在“ sorted(”阶段复制了整个字典在内存中的副本,因此,主要的迭代器好处似乎已经消失了:)

39

字典的键存储在哈希表中,这就是它们的“自然顺序”,即伪随机。任何其他顺序都是字典使用者的概念。

sorted()始终返回列表,而不是字典。如果将其传递给dict.items()(将生成一个元组列表),它将返回一个元组列表[[k1,v1),(k2,v2),...],可在循环中使用在某种程度上非常像一个字典,但无论如何它都不是一个字典

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

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

以下内容看起来像是循环中的字典,但事实并非如此,它是将元组解压缩为k,v的列表:

for k,v in sorted(foo.items()):
    print k, v

大致相当于:

for k in sorted(foo.keys()):
    print k, foo[k]

好的,但是我不需要Dict或List,而是想要Iterator。我如何强迫它成为迭代器?
迈克,

2
sorted(foo.keys())最好使用等效项sorted(foo),因为字典在迭代时会返回其键(可能具有不被迫创建foo.keys()中间列表的优势,这取决于sorted()可迭代对象的实现方式)。
Eric O Lebigot 2014年

我想知道哪种方法对速度和/或内存更有利,因为k in sorted(foo.keys()):它可以拉动键或for k,v in sorted(foo.items()):返回字典列表对的副本sorted(foo.keys())
CrandellWS

1
@CrandellWS:回答时间问题的最佳方法是使用Python timeit模块。
彼得·罗威尔

1
@frank-简短答案:否。dict是一个数组,其实际键为所提供键的值的哈希值。尽管有些实现可能是相当可预测的,有些甚至可能达成了这种约定,但在哈希排序方面我什么也没指望。有关3.6+行为的更多信息,请参见这篇文章。特别注意第一个答案。
彼得·罗威尔

31

格雷格的答案是正确的。请注意,在Python 3.0中,您必须

sorted(dict.items())

iteritems将不复存在。


我失败了:<type'exceptions.TypeError'>:iter()返回了'list'类型的非迭代器
Mike

3
“不要使用汽车,因为将来我们会有气垫板”
JJ

7

您现在也可以OrderedDict在Python 2.7中使用:

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

在这里,您将获得2.7版本的新功能页面和OrderedDict API


这将按插入顺序返回键值,而不是按排序顺序(即字母顺序)。
托尼·萨福克

5

通常,可以将这样的命令排序为:

for k in sorted(d):
    print k, d[k]

对于问题中的特定情况,对于d.iteritems()具有“替换”功能,请添加以下函数:

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

所以终点线从

return dict.iteritems()

return sortdict(dict)

要么

return sortdict(dict, reverse = True)

5
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

此方法仍然具有O(N log N)排序,但是,经过短暂的线性堆化后,它会按排序顺序生成项目,从理论上讲,当您不总是需要整个列表时,它会更加高效。



3

sorted返回一个列表,因此在尝试对其进行迭代时会出错,但是由于无法订购字典,因此必须处理列表。

我不知道您的代码的较大上下文是什么,但是您可以尝试将迭代器添加到结果列表中。像这样吗?:

return iter(sorted(dict.iteritems()))

当然,您现在将返回元组,因为排序使您的字典变成了元组列表

例如:说您的字典是: {'a':1,'c':3,'b':2} 排序后将其变成一个列表:

[('a',1),('b',2),('c',3)]

因此,当您实际遍历该列表时,您会返回(在本示例中)一个由字符串和整数组成的元组,但是至少您可以对它进行遍历。


2

假设您正在使用CPython 2.x并拥有一个较大的字典mydict,那么使用sorted(mydict)将会很慢,因为sorted会建立mydict键的排序列表。

在那种情况下,您可能要看一下我的orderdict包,其中包括sorteddictin C 的C实现。尤其是如果您必须在字典生命周期的不同阶段(即元素数)多次遍历键的排序列表时,请注意。

http://anthon.home.xs4all.nl/Python/ordereddict/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.