Відповіді:
Якщо його an, 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
повертає ітерабельний об'єкт перегляду зображень, а не список. Нам потрібно загорнути виклик у список, щоб зробити можливим індексацію
>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')
list(d.items())
list(d.items())
, скориставшись next(islice(d.items(), 1))
дістатися('bar', 'spam')
Чи потрібно використовувати OrdersDict або ви хочете спеціально тип, схожий на карту, який впорядкований якимось чином за допомогою швидкої позиційної індексації? Якщо останній, то розглянемо один із багатьох сортованих типів дикторів 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'
SortedDict
ключову функцію, щоб уникнути порівнянь. Як: SortedDict(lambda key: 0, ...)
. Ключі потім будуть несортованими, але залишаться у стабільному порядку та підлягають індексації.
Ось окремий випадок, якщо ви хочете, щоб перший запис (або близький до нього) в OrdersDict, без створення списку. (Це було оновлено до Python 3):
>>> from collections import OrderedDict
>>>
>>> d = OrderedDict()
>>> d["foo"] = "one"
>>> d["bar"] = "two"
>>> d["baz"] = "three"
>>> next(iter(d.items()))
('foo', 'one')
>>> next(iter(d.values()))
'one'
(Перший раз, коли ви говорите "наступний ()", це насправді означає "перший".)
У моєму неофіційному тесті next(iter(d.items()))
з невеликим OrderedDict лише трохи - трохи швидше , ніж items()[0]
. З OrdersDict в 10 000 записів next(iter(d.items()))
було приблизно в 200 разів швидше, ніж items()[0]
.
АЛЕ якщо ви збережете список елементів () один раз, а потім скористаєтесь списком багато, це може бути швидше. Або якщо ви неодноразово {створюйте ітератор елементів () та переходите до нього до потрібного положення}, це може бути повільніше.
OrderedDict
s не має iteritems()
методи, так що вам потрібно буде зробити наступне, щоб отримати перший елемент: next(iter(d.items()))
.
d.items()
не здається, що це ітератор, тож iter спереду не допоможе? Він все одно поверне повний список :(
odict_iterator
і мені було підтверджено на IRC #python, що це не робить копію списку.
Значно ефективніше використовувати IndexedOrderedDict з indexed
пакету.
Після коментаря Нікласа я зробив орієнтир на OrdersDict та 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 разів швидше в індексуванні елементів у конкретній позиції в цьому конкретному випадку.
indexed.py
замість indexed
.
Ця вікі спільноти намагається зібрати наявні відповіді.
Python 2.7
В Python 2, keys()
, values()
і items()
функції OrderedDict
списків повернення. Використовуючи values
як приклад, найпростіший спосіб
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"
Пакет 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 |
+--------+-----------+----------------+---------+
Пітон 3.6
У Python 3 є ті ж дві основні опції (список проти генератора), але методи 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, і мають аналогічні прискорення використання генераторів.
+--------+-----------+----------------+---------+
| size | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
| 1000 | .0316 | .0165 | .00262 |
| 10000 | .288 | .166 | .00294 |
| 100000 | 3.53 | 1.48 | .00332 |
+--------+-----------+----------------+---------+
Настала нова ера, і словники Python 3.6.1 тепер зберігають свій порядок. Ці семантики не є явними, оскільки для цього знадобиться схвалення BDFL. Але Реймонд Хеттінгер - це найкраща справа (і смішніше), і він робить досить вагомий випадок, що словники будуть замовлятись дуже довго.
Тому зараз легко створити фрагменти словника:
test_dict = {
'first': 1,
'second': 2,
'third': 3,
'fourth': 4
}
list(test_dict.items())[:2]
Примітка. Збереження порядку вставки диктонарів тепер офіційне в Python 3.7 .
для OrdersDict () ви можете отримати доступ до елементів шляхом індексації, отримуючи кортежі пар (ключ, значення) наступним чином або використовуючи ".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']
items
метод повертає об'єкт подання словника, а не список, і не підтримує нарізання чи індексацію. Тому вам доведеться спочатку перетворити його на список. docs.python.org/3.3/library/stdtypes.html#dict-views