2012-04-07 81 views
71

可以說我有下面的代碼:訪問項目在ordereddict

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

有沒有一種方法,我可以訪問項目的編號方式,比如:

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

回答

101

如果它的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') 
+0

好答案。列表是TheRightWay(tm)用於進行索引查找。 – 2012-04-07 22:10:07

+12

請注意,在3.x中,'items'方法返回一個可重用的字典視圖對象而不是列表,並且不支持切片或索引。所以你必須先把它變成一個列表。 http://docs.python.org/3.3/library/stdtypes.html#dict-views – 2013-06-05 21:51:55

+5

對於大型字典,將項目,值或鍵複製到列表中可能會很慢。我使用不同的內部數據結構重寫OrderedDict(),以便經常使用它:https://github.com/niklasf/indexed.py – Niklas 2013-09-06 20:07:29

18

你必須使用OrderedDict或者你特別希望的是在某些方面具有快速定位索引下令地圖樣類型?如果是後者,那麼考慮一下Python的許多排序詞典類型(它根據鍵排序順序對鍵值對進行排序)。一些實現也支持快速索引。例如,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' 
+3

感謝您讓我意識到sortedcontainers – mortbauer 2015-11-25 12:51:47

+1

您也可以使用帶有關鍵功能的'SortedDict'來避免比較。像:'SortedDict(lambda key:0,...)'。然後鍵將被排序,但將保持穩定的順序並且是可索引的。 – GrantJ 2016-01-04 23:48:46

8

這裏是一個特殊的情況下,如果你想第一條目(或接近)在OrderedDict,而無需創建一個列表:

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

(你第一次說「下一()「,它的意思是」第一「。)

在Python 2.7中的非正式測試中,帶有小OrderedDict的iteritems().next()只比items()[0]快一點點。對於10,000個條目的OrderedDict,iteritems().next()items()[0]快約200倍。

但是如果您保存items()列表一次,然後使用列表很多,那可能會更快。或者,如果你反覆{創建一個iteritems()迭代器並遍歷它到你想要的位置},那可能會更慢。

+5

Python 3'OrderedDict'沒有'iteritems()'方法,所以您需要執行以下操作來獲取第一個項目:'next(iter(d.items()))'。 – 2015-04-05 21:46:15

+0

在Python 3中'd.items()'似乎不是一個迭代器,所以在前面不會有幫助嗎?它仍然會返回完整列表:( – asksol 2016-06-21 00:42:20

+0

更新:我錯了,iter(d.items())返回'odict_iterator'並且在IRC#python上向我確認這不會生成列表的副本。 – asksol 2016-06-21 00:47:45

6

使用IndexedOrderedDict顯着更高效。

繼尼古拉斯的評論,我已經OrderedDictIndexedOrderedDict與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倍於在該特定情況下的具體位置標定元件。

+0

不錯!不幸的是在Anaconda。 – Konstantin 2017-07-12 08:41:08

+3

請注意,這是第三方軟件包:https://pypi.python.org/pypi/indexed.py – Epoc 2017-07-20 11:50:26

1

這是一個新時代,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] 
1

這個社區維基試圖收集現有的答案。

的Python 2.7

在Python 2,的OrderedDict返回列出了keys()values(),和items()功能。使用values爲例,最簡單的方法是

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

對於大集合,你只關心一個單一的指標,您可以使用生成的版本,iterkeysitervaluesiteritems避免創建完整的列表:

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

indexed.py包提供了IndexedOrderedDict,它是專爲這種用例設計的,並且是最快的選擇。

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

使用itervalues可以大大加快與隨機存取大型辭書:

$ 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

Python 3中具有相同的兩個基本選項(名單VS發電機),但字典方法默認返回生成器。

列表方法:

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" 

Python 3的詞典是一個數量級比蟒2更快,具有用於使用生成類似的加速比。

+--------+-----------+----------------+---------+ 
| size | list (ms) | generator (ms) | indexed | 
+--------+-----------+----------------+---------+ 
| 1000 | .0316  | .0165   | .00262 | 
| 10000 | .288  | .166   | .00294 | 
| 100000 | 3.53  | 1.48   | .00332 | 
+--------+-----------+----------------+---------+