wake-up-neo.com

Auf Elemente in Sammlungen zugreifen.OrderedDict nach Index

Sagen wir, ich habe den folgenden Code:

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

Gibt es eine Möglichkeit, auf die Elemente auf nummerierte Weise zuzugreifen, z. 

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

Wenn es eine OrderedDict() ist, können Sie einfach auf die Elemente zugreifen, indem Sie die Tupel von (Schlüssel-, Wert-) Paaren wie folgt abrufen

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

Hinweis für Python 3.X

dict.items würde ein iterable Dikt-Ansichtsobjekt anstatt einer Liste zurückgeben. Wir müssen den Anruf in eine Liste einschließen, um die Indizierung zu ermöglichen

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

Müssen Sie ein OrderedDict verwenden oder möchten Sie speziell einen kartentypartigen Typ, der auf irgendeine Weise mit schneller Positionsindexierung geordnet ist? Wenn letzteres, dann betrachten Sie einen der vielen sortierten Diktypen von Python (der Schlüsselwertpaare basierend auf der Schlüsselsortierreihenfolge ordnet). Einige Implementierungen unterstützen auch die schnelle Indizierung. Beispielsweise hat das Projekt sortierte Container nur für diesen Zweck den Typ 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

Hier ist ein Sonderfall, wenn Sie den first -Eintrag (oder einen ähnlichen Wert) in einem OrderedDict haben möchten, ohne eine Liste zu erstellen:

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

(Wenn Sie zum ersten Mal "next ()" sagen, bedeutet dies wirklich "first".)

In meinem informellen Test in Python 2.7 ist iteritems().next() mit einem kleinen OrderedDict nur ein kleines bisschen schneller als items()[0]. Mit einem OrderedDict von 10.000 Einträgen war iteritems().next() etwa 200-mal schneller als items()[0]

ABERWenn Sie die items () - Liste einmal speichern und sie dann häufig verwenden, könnte dies schneller sein. Wenn Sie wiederholt einen iteritems () - Iterator erstellen und ihn bis zur gewünschten Position durchlaufen, kann dies langsamer sein.

16

Die Verwendung von IndexedOrderedDict aus dem Paket indexed ist erheblich effizienter.

Nach Niklas Kommentar habe ich einen Benchmark für OrderedDict und IndexedOrderedDict mit 1000 Einträgen gemacht.

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 ist in diesem speziellen Fall bei der Indizierung von Elementen an bestimmten Positionen ~ 100-mal schneller.

13
刘金国

Dieses Community-Wiki versucht, vorhandene Antworten zu sammeln.

Python 2.7

In Python 2 geben die Funktionen keys(), values() und items() von OrderedDict Listen zurück. Am Beispiel von values ist der einfachste Weg

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

Bei großen Sammlungen, bei denen Sie nur einen einzelnen Index interessieren, können Sie die Erstellung der vollständigen Liste mit den Generatorversionen iterkeys, itervalues und iteritems vermeiden:

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

Das indexed.py package enthält IndexedOrderedDict, das für diesen Anwendungsfall entwickelt wurde und die schnellste Option ist.

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

Die Verwendung von itervalues ​​kann für große Wörterbücher mit wahlfreiem Zugriff erheblich schneller sein:

$ 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 hat die gleichen zwei grundlegenden Optionen (list vs generator), aber die dict-Methoden geben standardmäßig Generatoren zurück.

Listenmethode:

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

Generatormethode:

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

Python 3-Wörterbücher sind eine Größenordnung schneller als Python 2 und haben ähnliche Geschwindigkeitsstufen für die Verwendung von Generatoren.

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

Es ist eine neue Ära und mit Python 3.6.1 behalten Wörterbücher jetzt ihre Reihenfolge. Diese Semantik ist nicht explizit, da dies eine BDFL-Genehmigung erfordern würde. Aber Raymond Hettinger ist das nächstbeste (und lustigere) und er macht ein ziemlich starker Fall , dass Wörterbücher für eine sehr lange Zeit bestellt werden.

So ist es jetzt einfach, Slices eines Wörterbuchs zu erstellen:

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

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

Hinweis: Die Beibehaltung der diktonären Einfügereihenfolge ist jetzt offiziell in Python 3.7 .

5
highpost

für OrderedDict () können Sie auf die Elemente durch Indizieren zugreifen, indem Sie die Tupel von (Schlüssel-, Wert-) Paaren wie folgt abrufen oder '.values ​​()' verwenden.

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