Bir koleksiyondaki öğelere erişme.


142

Diyelim ki aşağıdaki kod var:

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

Öğelere numaralandırılmış bir şekilde erişebilmemin bir yolu var mı:

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

Yanıtlar:


181

Eğer onun bir OrderedDict()(anahtar, değer) çiftleri tuples aşağıdaki gibi elde ederek endeksleyerek öğeleri kolayca erişebilirsiniz

>>> 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 için not

dict.itemsbir liste yerine yinelenebilir bir dikte görüntüleme nesnesi döndürür . Endekslemeyi mümkün kılmak için çağrıyı bir listeye sarmamız gerekiyor

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

21
3.x'te itemsyöntemin bir liste yerine bir bütünleşik sözlük görüntüleme nesnesi döndürdüğünü ve dilimleme veya dizine eklemeyi desteklemediğini unutmayın. Bu yüzden önce listeye dönüştürmeniz gerekir. docs.python.org/3.3/library/stdtypes.html#dict-views
Peter

8
Öğeleri, değerleri veya anahtarları listelere kopyalamak büyük diktanlar için oldukça yavaş olabilir. Bunu çok sık yapmak zorunda olan uygulamalar için farklı bir iç veri yapısı ile OrderedDict () 'in yeniden yazılmasını oluşturdum: github.com/niklasf/indexed.py
Niklas

1
@PeterDeGlopper listeye nasıl çevirebilirim?
Dejell

1
@Dejel - yapıcıyı kullanın:list(d.items())
Peter

9
Yalnızca bir öğeye list(d.items())next(islice(d.items(), 1))('bar', 'spam')
erişirseniz

24

Bir OrderedDict kullanmak zorunda mısınız veya özellikle hızlı konum endeksleme ile bir şekilde sipariş edilen harita benzeri bir tip mi istiyorsunuz? İkincisi ise, Python'un sıralanmış birçok dikte türünü (anahtar sıralama düzenine göre anahtar / değer çiftleri sipariş eden) düşünün. Bazı uygulamalar hızlı indekslemeyi de destekler. Örneğin, sortcontainers projesi yalnızca bu amaç için bir SortedDict türüne sahiptir .

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

1
SortedDictKarşılaştırmaları önlemek için bir tuş işleviyle de kullanabilirsiniz . Gibi: SortedDict(lambda key: 0, ...). Anahtarlar daha sonra ayrıştırılır, ancak kararlı bir sırada kalır ve dizine eklenebilir.
GrantJ

19

Bir liste oluşturmadan bir OrderedDict'ta ilk girişi (veya buna yakın) istiyorsanız özel bir durum burada . (Bu Python 3 olarak güncellendi):

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

(İlk kez "next ()" demek, gerçekten "first" demek.)

Resmi olmayan next(iter(d.items()))testimde, küçük bir OrderedDict ile sadece biraz daha hızlı items()[0]. 10.000 girişlik OrderedDict ile next(iter(d.items()))200 kat daha hızlıydı items()[0].

AMA öğeler () listesini bir kez kaydedip listeyi çok kullanırsanız, bu daha hızlı olabilir. Veya tekrar tekrar {bir öğe () yineleyicisi oluşturup istediğiniz konuma getirin}, bu daha yavaş olabilir.


10
Python 3 OrderedDictler bir yok iteritems()ilk öğeyi elde etmek için aşağıdakileri yapmanız gerekir, böylece yöntemi: next(iter(d.items())).
Nathan Osman

Python 3'te d.items()bir yineleyici gibi görünmüyor, bu yüzden öndeki iter yardımcı olmayacak mı? Yine de listenin tamamını döndürecektir :(
asksol

1
Güncelleme: Yanılmışım, iter (d.items ()) geri döner odict_iteratorve IRC #python'da listenin bir kopyasını oluşturmadığını doğruladı.
asksol

@Nathan Osman, dürtmek için teşekkürler. Sonunda kendimi Python 3'e güncelledim!
SteveWithamDuplicate

14

Kullanımı dramatik daha verimlidir IndexedOrderedDict gelen indexedpaketin.

Niklas'ın yorumundan sonra , OrderedDict ve IndexedOrderedDict üzerinde 1000 giriş ile bir kıyaslama yaptım .

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 , bu özel durumda belirli bir konumdaki öğeleri indekslemede ~ 100 kat daha hızlıdır.


Güzel! Ne yazık ki henüz Anaconda'da değil.
Konstantin

1
@Konstantin Paketin gerçek adı indexed.py'dir . indexed.pyBunun yerine yüklemeyi deneyin indexed.
Sven Haile

9

Bu topluluk wiki mevcut yanıtları toplamaya çalışır.

Python 2.7

Piton 2'de, keys(), values(), ve items()işlevleri OrderedDictdönüş listeleri. valuesÖrnek olarak kullanmak , en basit yol

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

Yalnızca tek bir endeks umurumda büyük koleksiyonları için, jeneratör sürümlerini kullanan tam listesi oluşturma önleyebilirsiniz, iterkeys, itervaluesve iteritems:

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

İndexed.py paket sağlayan IndexedOrderedDictbu kullanım şeklini tasarlanmıştır ve en hızlı seçenek olacak.

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

Rasgele erişimli büyük sözlükler için itervalues ​​kullanmak oldukça hızlı olabilir:

$ 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 aynı iki temel seçeneğe sahiptir (list vs generator), ancak dikte yöntemleri varsayılan olarak jeneratörleri döndürür.

Liste yöntemi:

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

Jeneratör yöntemi:

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

Python 3 sözlükleri, python 2'den daha hızlı bir büyüklük sırasına sahiptir ve jeneratörleri kullanmak için benzer hızlandırmalara sahiptir.

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

7

Bu yeni bir dönem ve Python 3.6.1 ile sözlükler artık sıralarını koruyor. Bu anlambilim açık değildir, çünkü bu BDFL onayı gerektirir. Ama Raymond Hettinger bir sonraki en iyi şey (ve daha komik) ve oldukça güçlü bir dava yapıyor sözlüklerin çok uzun bir süre sipariş edileceği konusunda ortaya koyuyor.

Şimdi bir sözlük dilimi oluşturmak çok kolay:

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

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

Not: Dikte yerleştirme siparişi koruması artık Python 3.7'de resmidir .


0

OrderedDict () için, (anahtar, değer) çiftlerinin gruplarını aşağıdaki gibi alarak veya '.values ​​()' kullanarak dizin oluşturarak öğelere erişebilirsiniz.

>>> 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']
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.