Python 访问集合中的项目。按索引排序

Python 访问集合中的项目。按索引排序,python,collections,dictionary,python-3.x,ordereddictionary,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 如果它是一个orderedict(),您可以通过如下方式获取(键、值)对的元组,通过索引轻松访问元素 >>> import collections >>>

假设我有以下代码:

import collections
d = collections.OrderedDict()
d['foo'] = 'python'
d['bar'] = 'spam'
是否有办法以编号方式访问项目,如:

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

如果它是一个
orderedict()
,您可以通过如下方式获取(键、值)对的元组,通过索引轻松访问元素

>>> 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
将返回一个而不是一个列表。我们需要将调用包装到列表中,以使索引成为可能

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

您是否必须使用OrderedDict,或者您是否特别想要一种以某种方式通过快速位置索引进行排序的类似于地图的类型?如果是后者,那么考虑Python的许多排序的DICT类型之一(基于键排序顺序来命令键值对)。一些实现还支持快速索引。例如,项目有一个用于此目的的类型

>>> 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'

如果您希望OrderedICT中的第一个条目(或其附近的条目)不创建列表,那么这里有一个特例。(已更新为Python 3):

(你第一次说“next()”,实际上是指“first”。)

在我的非正式测试中,
next(iter(d.items())
和少量订购的dict只比
items()[0]
快一点点。订购了10000个条目,
next(iter(d.items())
的速度大约是
items()[0]
的200倍


但是如果只保存一次items()列表,然后多次使用该列表,则速度可能会更快。或者,如果您重复{创建一个items()迭代器并逐步执行到所需的位置},则速度可能会较慢。

从包中使用索引或直接添加会显著提高效率

在Niklas的评论之后,我对OrderedICTIndexedOrderedICT进行了基准测试,共有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
IndexedOrderAddict在这种特定情况下,在特定位置索引元素的速度大约快100倍


列出的其他解决方案需要额外的步骤
IndexedOrderedict
是对
Orderedict
的一种替代,只是它是可索引的。

这是一个新时代,随着Python 3.6.1的出现,词典现在保留了它们的顺序。这些语义并不明确,因为这需要BDFL的批准。但是雷蒙德·赫廷格是次好的(而且更有趣),他提出了一个建议,词典将被订购很长一段时间

因此,现在可以轻松创建字典片段:

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

list(test_dict.items())[:2]
注意:现在可以保留口述插入顺序。

此社区wiki尝试收集现有答案

Python 2.7

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

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

import itertools
next(itertools.islice(d.itervalues(), 0, 1))  # "python"
next(itertools.islice(d.itervalues(), 1, 2))  # "spam"
该软件包提供了
索引或直接添加
,该软件包专为此用例而设计,将是最快的选项

from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0]  # "python"
d.values()[1]  # "spam"
对于具有随机访问功能的大型词典,使用ITERVALUE可以大大加快速度:

$ 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  |
+--------+-----------+----------------+---------+
Python 3.6

Python3有两个相同的基本选项(list和generator),但是默认情况下dict方法返回generators

列表方法:

list(d.values())[0]  # "python"
list(d.values())[1]  # "spam"
生成器方法:

import itertools
next(itertools.islice(d.values(), 0, 1))  # "python"
next(itertools.islice(d.values(), 1, 2))  # "spam"
Python3字典比Python2快一个数量级,并且在使用生成器时有类似的加速

+--------+-----------+----------------+---------+
|  size  | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
|   1000 | .0316     | .0165          | .00262  |
|  10000 | .288      | .166           | .00294  |
| 100000 | 3.53      | 1.48           | .00332  |
+--------+-----------+----------------+---------+
对于OrderedDict(),您可以通过如下方式获取(键,值)对的元组或使用“.values()”进行索引来访问元素


如果您正在处理预先知道的固定数量的键,请使用Python的内置代码。一个可能的用例是,当您希望存储一些常量数据并通过索引和指定键在整个程序中访问它时

导入集合
有序_键=['foo','bar']
D=集合。命名为双('D',有序\U键)
d=d(foo='python',bar='spam')
通过索引进行访问: 通过指定密钥进行访问: 或者更好:

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

如果安装了pandas,则可以将订购的dict转换为pandas
系列
。这将允许随机访问字典元素

>>> 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

请注意,在3.x中,
items
方法返回一个交互式字典视图对象,而不是列表,并且不支持切片或索引。所以你必须先把它变成一个列表。对于大型录音机来说,将项目、值或键复制到列表中可能非常慢。我使用不同的内部数据结构为经常需要这样做的应用程序创建了OrderedDict()的重写:@PeterDeGlopper如何将其转换为列表?@Dejel-使用构造函数:
list(d.items())
如果只访问一个项,可以通过使用
next来避免
list(d.items())
的内存开销(islice(d.items(),1))
要获取
('bar','spam')
python3
orderedict
s没有
iteritems()
方法,因此需要执行以下操作才能获取第一项:
next(iter(d.items())
。在python3中
d.items()
似乎不是迭代器,所以前面的iter不会有帮助吗?它仍然会返回完整的列表:(更新:我错了,iter(d.items())返回
odict_迭代器
,并在IRC#python上向我确认这不是列表的副本。@Nathan Osman,谢谢你的提示。我最近终于更新到了python 3!你也可以使用带有键函数的
sortedict
,以避免比较。例如:
sortedict(lambda键:0,…)
。然后,密钥将被取消排序,但将保持稳定的顺序并可索引。很好!不幸的是,还没有在Anaconda中。@Konstantin包的实际名称是index.py.T
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
>>> 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