Truy cập các mục trong một bộ sưu tập.OrderedDict theo chỉ mục


142

Hãy nói rằng tôi có mã sau đây:

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

Có cách nào để tôi có thể truy cập các mục theo cách được đánh số, như:

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

Câu trả lời:


181

Nếu đó là một OrderedDict()bạn có thể dễ dàng truy cập các phần tử bằng cách lập chỉ mục bằng cách lấy các bộ dữ liệu của các cặp (khóa, giá trị) như sau

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

Lưu ý cho Python 3.X

dict.itemssẽ trả về một đối tượng xem chính tả lặp đi lặp lại thay vì một danh sách. Chúng tôi cần phải kết thúc cuộc gọi vào một danh sách để có thể lập chỉ mục

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

21
Lưu ý rằng trong 3.x itemsphương thức trả về một đối tượng xem từ điển có thể thay thế thay vì một danh sách và không hỗ trợ cắt hoặc lập chỉ mục. Vì vậy, bạn phải biến nó thành một danh sách đầu tiên. docs.python.org/3.3/l Library / stdtypes.html
dict-view

8
Sao chép các mục, giá trị hoặc khóa vào danh sách có thể khá chậm đối với các biểu tượng lớn. Tôi đã tạo một bản viết lại của OrderedDict () với cơ sở hạ tầng nội bộ khác cho các ứng dụng phải thực hiện việc này rất thường xuyên: github.com/niklasf/indexed.py
Niklas

1
@PeterDeGlopper làm cách nào để biến nó thành một danh sách?
Dejell

1
@Dejel - sử dụng hàm tạo:list(d.items())
Peter DeGlopper

8
Nếu bạn chỉ truy cập một mục, bạn có thể tránh được chi phí bộ nhớ list(d.items())bằng cách sử dụng next(islice(d.items(), 1))để nhận('bar', 'spam')
Quantum7

24

Bạn có phải sử dụng OrderedDict hay bạn đặc biệt muốn một loại giống như bản đồ được sắp xếp theo cách nào đó với lập chỉ mục vị trí nhanh? Nếu sau này, hãy xem xét một trong nhiều loại chính tả được sắp xếp của Python (sắp xếp các cặp giá trị khóa dựa trên thứ tự sắp xếp khóa). Một số triển khai cũng hỗ trợ lập chỉ mục nhanh. Ví dụ, dự án sortcontainers có loại SortedDict cho mục đích này.

>>> 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
Bạn cũng có thể sử dụng SortedDictvới một chức năng chính để tránh so sánh. Giống như : SortedDict(lambda key: 0, ...). Các khóa sau đó sẽ không được sắp xếp nhưng sẽ vẫn ở trạng thái ổn định và có thể lập chỉ mục.
GrantJ

19

Đây là trường hợp đặc biệt nếu bạn muốn mục đầu tiên (hoặc gần với nó) trong OrderedDict, mà không tạo danh sách. (Điều này đã được cập nhật lên 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'

(Lần đầu tiên bạn nói "next ()", nó thực sự có nghĩa là "lần đầu tiên.")

Trong thử nghiệm không chính thức của tôi, next(iter(d.items()))với một OrderedDict nhỏ chỉ nhanh hơn một chút items()[0]. Với OrderedDict gồm 10.000 mục, next(iter(d.items()))nhanh hơn khoảng 200 lần items()[0].

NHƯNG nếu bạn lưu danh sách các mặt hàng () một lần và sau đó sử dụng danh sách rất nhiều, điều đó có thể nhanh hơn. Hoặc nếu bạn lặp đi lặp lại {tạo một trình vòng lặp vật phẩm () và bước qua nó đến vị trí bạn muốn}, điều đó có thể chậm hơn.


10
Python 3 OrderedDictkhông có một iteritems()phương thức, vì vậy bạn sẽ cần phải làm như sau để có được mục đầu tiên : next(iter(d.items())).
Nathan Osman

Trong Python 3 d.items()dường như không phải là một trình vòng lặp, vậy iter ở phía trước sẽ không giúp ích gì? Nó vẫn sẽ trả về danh sách đầy đủ :(
Askol

1
Cập nhật: Tôi đã sai, iter (d.items ()) trả lại odict_iteratorvà được xác nhận với tôi trên IRC #python rằng điều này không tạo ra một bản sao của danh sách.
Askol

@Nathan Osman, cảm ơn vì sự nũng nịu. Cuối cùng tôi đã cập nhật lên Python 3 gần đây!
SteveWithamD trùng lặp

14

Nó hiệu quả hơn đáng kể khi sử dụng IndexedOrderedDict từ indexedgói.

Theo nhận xét của Niklas, tôi đã thực hiện một điểm chuẩn trên OrderedDictIndexedOrderedDict với 1000 mục.

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 nhanh hơn ~ 100 lần trong các phần tử lập chỉ mục ở vị trí cụ thể trong trường hợp cụ thể này.


Đẹp! Chưa may ở Anaconda.
Konstantin

1
@Konstantin Tên thực tế của gói là indexed.py . Hãy thử cài đặt indexed.pythay vì indexed.
Sven Haile

9

Wiki cộng đồng này cố gắng thu thập các câu trả lời hiện có.

Python 2.7

Trong python 2, keys(), values(), và items()chức năng của OrderedDictdanh sách trở lại. Sử dụng valueslàm ví dụ, cách đơn giản nhất là

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

Đối với các bộ sưu tập rộng lớn, nơi bạn chỉ quan tâm đến một chỉ số duy nhất, bạn có thể tránh tạo ra danh sách đầy đủ bằng cách sử dụng các phiên bản máy phát điện, iterkeys, itervaluesiteritems:

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

Các indexed.py gói cung cấp IndexedOrderedDict, được thiết kế đối với trường hợp sử dụng này và sẽ là lựa chọn nhanh nhất.

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

Sử dụng itervalues ​​có thể nhanh hơn đáng kể cho các từ điển lớn với quyền truy cập ngẫu nhiên:

$ 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 có hai tùy chọn cơ bản giống nhau (danh sách so với trình tạo), nhưng các phương thức dict trả về các trình tạo theo mặc định.

Danh sách phương pháp:

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

Phương pháp máy phát điện:

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

Từ điển Python 3 là một thứ tự có độ lớn nhanh hơn python 2 và có tốc độ tương tự để sử dụng máy phát điện.

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

7

Đó là một kỷ nguyên mới và với từ điển Python 3.6.1 hiện vẫn giữ trật tự của chúng. Những ngữ nghĩa này không rõ ràng bởi vì điều đó sẽ yêu cầu phê duyệt BDFL. Nhưng Raymond Hettinger là điều tốt nhất tiếp theo (và hài hước hơn) và anh ấy làm một vụ án khá mạnh mẽ rằng từ điển sẽ được đặt hàng trong một thời gian rất dài.

Vì vậy, bây giờ thật dễ dàng để tạo các lát của một từ điển:

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

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

Lưu ý: Bảo quản thứ tự chèn Dictonary hiện là chính thức trong Python 3.7 .


0

đối với OrderedDict () bạn có thể truy cập các phần tử bằng cách lập chỉ mục bằng cách lấy các bộ dữ liệu của các cặp (khóa, giá trị) như sau hoặc sử dụng '.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']
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.