Python中如何选择有序字典(OrderedDict)的第i个元素?

21

我有一段代码可以按字母顺序对字典进行排序。是否有一种方法可以选择有序字典中的第i个键并返回其相应的值?即

import collections
initial = dict(a=1, b=2, c=2, d=1, e=3)
ordered_dict = collections.OrderedDict(sorted(initial.items(), key=lambda t: t[0]))
print(ordered_dict)

OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])

我希望有一些类似于...的功能。

select = int(input("Input dictionary index"))
#User inputs 2
#Program looks up the 2nd entry in ordered_dict (c in this case)
#And then returns the value of c (2 in this case)

这该怎么实现呢?谢谢。
(类似于访问有序字典中的项,但我只想输出键值对中的值。)

尝试使用 ordered_dict[ordered_dict.keys()[index]] - Ionut Hulub
@IonutHulub,我尝试过(没有用户输入部分)print(ordered_dict[ordered_dict.keys()[2]]),但是收到了错误提示:TypeError: "KeysView" object does not support indexing。 - Pingk
“lambda” 在拼写时需要在 “d” 前面加上 “b”。 - Daniel Lee
@DanielLee 对不起,已经更正。 - Pingk
如果输入的索引很小,您可以通过使用 heapq 避免对整个 initial 字典进行排序:result = initial[heapq.nsmallest(select+1, initial)[-1]] - jfs
5个回答

26

在Python 2中:

如果你想访问键(key):

>>> ordered_dict = OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])
>>> ordered_dict.keys()[2]
'c'
如果想要访问该值:
>>> ordered_dict.values()[2]
2
如果您正在使用Python 3,您可以通过将keys方法返回的KeysView对象包装成列表来进行转换:
>>> list(ordered_dict.keys())[2]
'c'
>>> list(ordered_dict.values())[2]
2

不是最完美的解决方案,但它能够起作用。


12

使用itertools.islice在这里是高效的,因为我们不必为了下标创建任何中间列表。

from itertools import islice
print(next(islice(ordered_dict.items(), 2, None)))

如果您只想要值,可以这样做

print ordered_dict[next(islice(ordered_dict, 2, None))]

啊,不太对。你的方法返回键值对,但我只想让代码返回_键的值_。 - Pingk
+1. islice 更可取,但对于小字典 list(ordered_dict.values())[2] 可能更快,即在测量之前不要假设哪个更快。 - jfs
@JFSebastian,有趣,islice在小字典中的优势是什么?只是代码背后的逻辑还是其他原因? - Pingk
1
@Pingk 说,“islice” 更可取,但不适用于小字典。 - thefourtheye
抱歉,我读错了,但相比列表,它是什么使它更快/更慢?@thefourtheye - Pingk
使用键索引真的比在.values上使用islice更快吗? - Janus Troelsen

6
您是否必须使用OrderedDict,还是只需要支持索引的类似dict的类型?如果后者,则考虑使用sorted dict对象。一些SortedDict的实现(根据键排序顺序排序对)支持快速的第n个索引。例如,sortedcontainers项目具有带有随机访问索引的SortedDict类型。
在您的情况下,它应该看起来像这样:
>>> from sortedcontainers import SortedDict
>>> sorted_dict = SortedDict(a=1, b=2, c=2, d=1, e=3)
>>> print sorted_dict.iloc[2]
'c'

如果您要进行大量查找,使用这种方法会比重复迭代到所需索引要快得多。

非常感谢,我将来可能会用到这个方法,但是我记录为正确答案的方法与此非常相似。 不过我很好奇,如果我更改其中一个键值对的值,字典是否会保持有序,还是像标准字典一样重新排列? - Pingk
是的,它会自动按键排序。如果您对字典进行编辑,然后索引,它比已接受的解决方案快得多。 - GrantJ
太棒了,下次我可能会用这个。我不认为我会改变接受的答案,但我会给你投票支持。 - Pingk

1
您可以按照以下方式操作(od是有序字典):
def get_idx(od, idx):
   from itertools import islice
   idx = (idx + len(od)) % len(od)
   t = islice(od.items(), idx, idx + 1)
   return next(t)

>>>x

OrderedDict([('a', 2), ('b', 3), ('k', 23), ('t', 41), ('q', 23)])

>>>get_idx(x, 1)
('b', 3)
>>>get_idx(x, 2)
('k', 23)
>>>get_idx(x, 4)
('q', 23)
>>>get_idx(x, -1)
('q', 23)
>>>get_idx(x, -2)
('t', 41)

0

不要低估一个简单的for循环:

from collections import OrderedDict

od=OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1), ('e', 3)])

def ith(od, tgt):
    for i, t in enumerate(od.items()):
        if i==tgt:
            print('element {}\'s key is "{}"'.format(i,t[0]))
            break
    else:
        print('element {} not found'.format(tgt)) 

ith(od, 2)
# element 2's key is "c"
ith(od, 20) 
# element 20 not found

这里的优点是,一旦找到所需的元素,循环就会中断,并且如果未找到,则返回一个合理的结果...

缺点是不支持相对切片。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接