web-dev-qa-db-ja.com

collections.OrderedDict内のアイテムへのインデックスによるアクセス

次のコードがあるとしましょう:

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

次のような番号付きの方法でアイテムにアクセスする方法はありますか?

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

OrderedDict()の場合、次のように(key、value)ペアのタプルを取得することにより、インデックスを作成することで簡単に要素にアクセスできます

>>> 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は、リストではなく 反復可能なdictビューオブジェクト を返します。インデックス付けを可能にするために、呼び出しをリストにラップする必要があります

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

OrderedDictを使用する必要がありますか、それとも高速位置インデックス付けで何らかの方法で順序付けられたマップのようなタイプが必要ですか?後者の場合、Pythonの多数のソートされたdictタイプ(キーのソート順に基づいてキーと値のペアを順序付けする)の1つを検討します。一部の実装では、高速なインデックス作成もサポートしています。たとえば、 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'
23
GrantJ

リストを作成せずに、OrderedDictのfirstエントリ(またはそれに近い)が必要な場合の特別なケースを次に示します。

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

(最初に「next()」と言うとき、それは本当に「first」を意味します。)

Python 2.7の非公式のテストでは、小さなOrderedDictを使用したiteritems().next()は、items()[0]よりもほんの少しだけ高速です。 OrderedDictが10,000エントリの場合、iteritems().next()items()[0]より約200倍高速でした。

BUT items()リストを一度保存​​してからそのリストを大量に使用すると、より高速になります。または、{iteritems()反復子を作成し、それをステップ実行して目的の位置に移動する}場合、それは遅くなる可能性があります。

17

indexed パッケージのIndexedOrderedDictを使用する方が劇的に効率的です。

Niklasのコメントに続いて、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倍高速です。

13
刘金国

このコミュニティwikiは、既存の回答を収集しようとします。

Python 2.7

python 2では、OrderedDictkeys()values()、およびitems()関数がリストを返します。 valuesを例として使用すると、最も簡単な方法は

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

単一のインデックスのみに関心がある大規模なコレクションの場合、ジェネレーターのバージョンiterkeysitervaluesおよびiteritemsを使用して完全なリストを作成することを回避できます。

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には同じ2つの基本オプション(リストとジェネレーター)がありますが、dictメソッドはデフォルトでジェネレーターを返します。

リスト方式:

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の辞書はpython 2よりも1桁高速であり、ジェネレーターを使用する場合と同様の高速化があります。

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

これは新しい時代であり、Python 3.6.1の辞書は順序を保持するようになりました。これらのセマンティクスは、BDFLの承認が必要になるため、明示的ではありません。しかし、レイモンド・ヘッティンガーは次善の策(そして面白く)であり、彼は かなり強いケース を作り、辞書は非常に長い間注文されるでしょう。

したがって、辞書のスライスを簡単に作成できるようになりました。

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

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

注:現在、辞書挿入順序の保存は 公式のPython 3.7 です。

5
highpost

orderedDict()の場合、次のように(key、value)ペアのタプルを取得するか、「。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']
0
Mehar Rahim