web-dev-qa-db-fra.com

Accéder aux éléments d'une collection.OrderedDict par index

Disons que j'ai le code suivant:

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

Puis-je accéder aux éléments de manière numérotée, comme par exemple: 

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

Si c'est un OrderedDict() vous pouvez facilement accéder aux éléments en indexant en obtenant les n-uplets des paires (clé, valeur) comme suit

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

Note pour Python 3.X

dict.items renverrait un objet de vue dictable itérable plutôt qu'une liste. Nous devons placer l’appel sur une liste afin de permettre l’indexation.

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

Devez-vous utiliser un OrdreDict ou voulez-vous spécifiquement un type de type carte ordonné d'une manière ou d'une autre avec une indexation de position rapide? Dans ce dernier cas, considérez l'un des nombreux types dict triés de Python (qui classe les paires clé-valeur en fonction de l'ordre de tri des clés). Certaines implémentations prennent également en charge l'indexation rapide. Par exemple, le projet sortContainers a un type SortedDict uniquement à cette fin.

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

Voici un cas particulier si vous souhaitez que l'entrée first (ou proche de celle-ci) soit dans un OrderedDict, sans créer de liste:

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

(La première fois que vous dites "next ()", cela signifie vraiment "premier".)

Dans mon test informel en Python 2.7, iteritems().next() avec un petit OrderedDict n'est qu'un tout petit peu plus rapide que items()[0]. Avec un ordre ordonné de 10 000 entrées, iteritems().next() était environ 200 fois plus rapide que items()[0]

MAISsi vous enregistrez la liste items () une fois puis que vous utilisez beaucoup la liste, cela pourrait être plus rapide. Ou si vous créez à plusieurs reprises {un itérateur iteritems () et le parcourez jusqu'à la position souhaitée}, cela pourrait être plus lent.

16

Il est nettement plus efficace d’utiliser IndexedOrderedDict à partir de indexed package.

Suite au commentaire de Niklas, j'ai effectué un test d'évaluation sur OrderedDict et IndexedOrderedDict avec 1 000 entrées.

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 est environ 100 fois plus rapide pour l'indexation des éléments à une position spécifique dans ce cas particulier.

13
刘金国

_ {Ce wiki de communauté tente de rassembler les réponses existantes.

Python 2.7

En python 2, les fonctions keys(), values() et items() des listes de retournements OrderedDict. En utilisant values comme exemple, le moyen le plus simple est

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

Pour les collections volumineuses ne concernant qu'un seul index, vous pouvez éviter de créer la liste complète à l'aide des versions du générateur, iterkeys, itervalues et iteritems:

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

Le paquet indexed.py package fournit IndexedOrderedDict, conçu pour ce cas d'utilisation et sera l'option la plus rapide.

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

L'utilisation des itervalues ​​peut être considérablement plus rapide pour les grands dictionnaires à accès aléatoire:

$ 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 a les deux mêmes options de base (list vs generator), mais les méthodes dict renvoient des générateurs par défaut.

Méthode de liste:

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

Méthode du générateur:

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

Les dictionnaires Python 3 sont d'un ordre de grandeur plus rapide que Python 2 et ont des accélérations similaires pour l'utilisation de générateurs.

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

C'est une nouvelle ère et avec les dictionnaires Python 3.6.1, ils conservent désormais leur ordre. Cette sémantique n'est pas explicite, car cela nécessiterait l'approbation de BDFL. Mais Raymond Hettinger est la deuxième meilleure chose (et plus drôle) et il fait un assez solide argument que les dictionnaires seront commandés très longtemps.

Alors maintenant, il est facile de créer des tranches de dictionnaire:

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

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

Remarque: La conservation d'ordre d'ordre d'insertion dans un dictionnaire est désormais officiel dans Python 3.7 .

4
highpost

pour OrderedDict (), vous pouvez accéder aux éléments en indexant en obtenant les nuplets des paires (clé, valeur) comme suit ou en utilisant '.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