Dostęp do elementów w zamówieniu

Powiedzmy, że mam następujący kod:

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

Czy Jest jakiś sposób, aby uzyskać dostęp do przedmiotów w sposób numerowany, jak:

d(0) #foo's Output
d(1) #bar's Output
Author: x29a, 2012-04-08

6 answers

Jeśli jego an OrderedDict() możesz łatwo uzyskać dostęp do elementów, indeksując, uzyskując krotki par (klucz, wartość) w następujący sposób

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

Uwaga dla Pythona 3.X

dict.items zwraca iterable dict view object zamiast listy. Musimy zawinąć wywołanie na Listę w celu umożliwienia indeksowania

>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')
 118
Author: Abhijit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-04 03:21:26

Czy musisz użyć OrderedDict, czy chcesz typ mapy, który jest w jakiś sposób uporządkowany z szybkim indeksowaniem pozycyjnym? Jeśli to ostatnie, rozważ jeden z wielu sortowanych typów dict Pythona (który porządkuje pary klucz-wartość na podstawie kolejności sortowania kluczy). Niektóre implementacje obsługują również szybkie indeksowanie. Na przykład projekt sortedcontainers mA typ SortedDict właśnie do tego celu.

>>> 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'
 20
Author: GrantJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-08 04:29:40

Oto specjalny przypadek, jeśli chcesz pierwszy wpis (lub blisko niego) w OrderedDict, bez tworzenia listy:

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

(Kiedy pierwszy raz mówisz " next ()", to naprawdę oznacza " pierwszy.")

W moim nieformalnym teście w Pythonie 2.7, iteritems().next() z małym OrderedDict jest tylko trochę szybszy niż items()[0]. Przy zamówieniu 10 000 wejść, iteritems().next() był około 200 razy szybszy niż items()[0].

Ale Jeśli zapiszesz listę items () raz, a następnie będziesz często z niej korzystać, to może być szybsze. Lub jeśli wielokrotnie {tworzysz iterator iteritems () i przechodzisz przez niego do żądanej pozycji }, może to być wolniejsze.

 14
Author: SteveWithamDuplicate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-29 19:38:10

Znacznie bardziej efektywne jest użycie IndexedOrderedDict .

Po komentarzu Niklasa, zrobiłem benchmark OrderedDict i IndexedOrderedDict z 1000 wpisami.

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 jest ~100 razy szybszy w indeksowaniu elementów na określonej pozycji w tym konkretnym przypadku.

 8
Author: 刘金国,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-15 13:06:02

ta wiki społeczności próbuje zebrać istniejące odpowiedzi.

Python 2.7

W Pythonie 2, the keys(), values(), i items() Funkcje listy zwrotnej OrderedDict. Używając values jako przykład, najprostszym sposobem jest

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

W przypadku dużych kolekcji, w których zależy Ci tylko na jednym indeksie, możesz uniknąć tworzenia pełnej listy za pomocą wersji generatora, iterkeys, itervalues i iteritems:

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

The indexed.py pakiet zapewnia IndexedOrderedDict, który jest przeznaczony do tego przypadku użycia i będzie najszybszą opcją.

from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0]  # "python"
d.values()[1]  # "spam"
Użycie itervalues może być znacznie szybsze dla dużych słowników z losowym dostępem:
$ 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 ma te same dwie podstawowe opcje (list vs generator), ale metody dict domyślnie zwracają Generatory.

Metoda listy:

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

Metoda generatora:

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

Słowniki Pythona 3 są o rząd wielkości szybsze niż python 2 i mają podobne przyspieszenie do korzystania z generatorów.

+--------+-----------+----------------+---------+
|  size  | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
|   1000 | .0316     | .0165          | .00262  |
|  10000 | .288      | .166           | .00294  |
| 100000 | 3.53      | 1.48           | .00332  |
+--------+-----------+----------------+---------+
 5
Author: Quantum7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 14:30:14

To nowa era, a w Pythonie 3.6.1 słowniki zachowują swoją kolejność. Te semantyki nie są jednoznaczne, ponieważ wymagałoby to zatwierdzenia przez BDFL. Ale Raymond Hettinger jest kolejną najlepszą rzeczą (i zabawniejszą) i robi dość mocną sprawę , że słowniki będą zamawiane przez bardzo długi czas.

Więc teraz łatwo jest stworzyć słownik:

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

list(test_dict.items())[:2]
 2
Author: highpost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 06:39:17