按索引访问collections.OrderedDict中的项目

时间:2012-04-07 20:34:19

标签: python collections dictionary python-3.x ordereddictionary

假设我有以下代码:

import collections
d = collections.OrderedDict()
d['foo'] = 'python'
d['bar'] = 'spam'

我是否有办法以编号的方式访问这些项目,例如:

d(0) #foo's Output
d(1) #bar's Output

9 个答案:

答案 0 :(得分:148)

如果它是OrderedDict(),您可以通过索引(键,值)对的索引来轻松访问元素,如下所示

>>> import collections
>>> d = collections.OrderedDict()
>>> d['foo'] = 'python'
>>> d['bar'] = 'spam'
>>> d.items()
[('foo', 'python'), ('bar', 'spam')]
>>> d.items()[0]
('foo', 'python')
>>> d.items()[1]
('bar', 'spam')

请注意Python 3.X

dict.items会返回iterable dict view object而不是列表。我们需要将调用包装到列表中以使索引成为可能

>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')

答案 1 :(得分:23)

您是否必须使用OrderedDict,或者您是否特别想要一种类似地图的类型,以某种方式使用快速位置索引进行排序?如果是后者,那么考虑一下Python的许多排序的dict类型(它根据键排序顺序对键值对进行排序)。某些实现还支持快速索引。例如,sortedcontainers项目就具有SortedDict类型,仅用于此目的。

>>> from sortedcontainers import SortedDict
>>> sd = SortedDict()
>>> sd['foo'] = 'python'
>>> sd['bar'] = 'spam'
>>> print sd.iloc[0] # Note that 'bar' comes before 'foo' in sort order.
'bar'
>>> # If you want the value, then simple do a key lookup:
>>> print sd[sd.iloc[1]]
'python'

答案 2 :(得分:16)

如果你想在OrderedDict中输入第一个条目(或接近它)而不创建列表,这是一个特例:

>>> from collections import OrderedDict
>>> 
>>> d = OrderedDict()
>>> d["foo"] = "one"
>>> d["bar"] = "two"
>>> d["baz"] = "three"
>>> 
>>> d.iteritems().next()
('foo', 'one')

(你第一次说" next()",它真的意味着"首先。")

在Python 2.7中的非正式测试中,带有小型OrderedDict的iteritems().next()只比items()[0]快一点点。对于10,000个条目的OrderedDict,iteritems().next()items()[0]快约200倍。

但是如果您保存items()列表一次然后再使用该列表,那可能会更快。或者,如果您反复{创建一个iteritems()迭代器并逐步执行它到您想要的位置},那可能会更慢。

答案 3 :(得分:13)

使用indexed包中的 IndexedOrderedDict 效率要高得多。

根据Niklas的评论,我在 OrderedDict IndexedOrderedDict 上做了1000个条目的基准测试。

In [1]: from numpy import *
In [2]: from indexed import IndexedOrderedDict
In [3]: id=IndexedOrderedDict(zip(arange(1000),random.random(1000)))
In [4]: timeit id.keys()[56]
1000000 loops, best of 3: 969 ns per loop

In [8]: from collections import OrderedDict
In [9]: od=OrderedDict(zip(arange(1000),random.random(1000)))
In [10]: timeit od.keys()[56]
10000 loops, best of 3: 104 µs per loop
在这种特定情况下,

IndexedOrderedDict 在特定位置的索引元素的速度要快约100倍。

答案 4 :(得分:8)

此社区维基试图收集现有答案。

Python 2.7

在python 2中,keys()的{​​{1}},values()items()函数返回列表。以OrderedDict为例,最简单的方法是

values

对于您只关心单个索引的大型集合,您可以避免使用生成器版本d.values()[0] # "python" d.values()[1] # "spam" iterkeysitervalues创建完整列表:

iteritems

indexed.py包提供import itertools next(itertools.islice(d.itervalues(), 0, 1)) # "python" next(itertools.islice(d.itervalues(), 1, 2)) # "spam" ,专为此用例而设计,是最快的选择。

IndexedOrderedDict

对于具有随机访问权限的大型词典,使用itervalues可能会快得多:

from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0]  # "python"
d.values()[1]  # "spam"

Python 3.6

Python 3具有相同的两个基本选项(list vs generator),但dict方法默认返回生成器。

列出方法:

$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 1000;   d = OrderedDict({i:i for i in range(size)})'  'i = randint(0, size-1); d.values()[i:i+1]'
1000 loops, best of 3: 259 usec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 10000;  d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i:i+1]'
100 loops, best of 3: 2.3 msec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 100000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i:i+1]'
10 loops, best of 3: 24.5 msec per loop

$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 1000;   d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
10000 loops, best of 3: 118 usec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 10000;  d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
1000 loops, best of 3: 1.26 msec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 100000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
100 loops, best of 3: 10.9 msec per loop

$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 1000;   d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.19 usec per loop
$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 10000;  d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.24 usec per loop
$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 100000; d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.61 usec per loop

+--------+-----------+----------------+---------+
|  size  | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
|   1000 | .259      | .118           | .00219  |
|  10000 | 2.3       | 1.26           | .00224  |
| 100000 | 24.5      | 10.9           | .00261  |
+--------+-----------+----------------+---------+

生成方法:

list(d.values())[0]  # "python"
list(d.values())[1]  # "spam"

Python 3字典比python 2快一个数量级,并且使用生成器具有类似的加速。

import itertools
next(itertools.islice(d.values(), 0, 1))  # "python"
next(itertools.islice(d.values(), 1, 2))  # "spam"

答案 5 :(得分:4)

这是一个新时代,Python 3.6.1词典现在保留了他们的订单。这些语义不明确,因为这需要BDFL批准。但是Raymond Hettinger是下一个最好的东西(而且更有趣),他制作了一个pretty strong case字典将被订购很长一段时间。

所以现在创建字典片很容易:

test_dict = {
                'first':  1,
                'second': 2,
                'third':  3,
                'fourth': 4
            }

list(test_dict.items())[:2]

注意: Dictonary insert-order preserve现在为official in Python 3.7

答案 6 :(得分:1)

如果您要使用预先知道的固定键数,请改用Python的内置namedtuples。一个可能的用例是当您要存储一些恒定数据并通过索引和指定键在整个程序中访问它们时。

import collections
ordered_keys = ['foo', 'bar']
D = collections.namedtuple('D', ordered_keys)
d = D(foo='python', bar='spam')

通过索引访问:

d[0] # result: python
d[1] # result: spam

通过指定键进行访问:

d.foo # result: python
d.bar # result: spam

或更佳:

getattr(d, 'foo') # result: python
getattr(d, 'bar') # result: spam

答案 7 :(得分:1)

如果已安装pandas,则可以将订购的字典转换为熊猫Series。这将允许随机访问字典元素。

>>> import collections
>>> import pandas as pd
>>> d = collections.OrderedDict()
>>> d['foo'] = 'python'
>>> d['bar'] = 'spam'

>>> s = pd.Series(d)

>>> s['bar']
spam
>>> s.iloc[1]
spam
>>> s.index[1]
bar

答案 8 :(得分:0)

对于OrderedDict(),您可以通过按以下方式获取(键,值)对的元组或通过使用'.values()'进行索引来访问元素。

>>> import collections
>>> d = collections.OrderedDict()
>>> d['foo'] = 'python'
>>> d['bar'] = 'spam'
>>> d.items()
[('foo', 'python'), ('bar', 'spam')]
>>>d.values()
odict_values(['python','spam'])
>>>list(d.values())
['python','spam']