Python-从字典返回前N个key:value对


108

考虑以下字典d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

我想从d返回前N个key:value对(在这种情况下,N <= 4)。最有效的方法是什么?


1
警告。答案中似乎有很多错误信息。我的测试表明,没有一个解决方案比更快list(d.items())[:4]。list()是许多答案的基础实现。
BSalita

Answers:


114

不需要“前n个”键,因为a dict不会记住首先插入的键。

你可以任意 n键-值对,但:

n_items = take(n, d.iteritems())

这使用take来自itertools配方的实现:

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

看到它在线上工作:ideone


Python 3.6更新

n_items = take(n, d.items())

42
我相信iteritems应替换items为乡亲关于Python 3
莫妮卡Heddneck

1
@MonicaHeddneck,太棒了,谢谢您添加此评论。
卡尔·贝克

11
这里的初学者take()-python代码库的一部分在任何地方吗?还是纯粹是您在此处的答案中定义的功能?询问它是否是代码库的一部分,我无法找到/导入它。:)
Scott Borden

80

检索任何内容的一种非常有效的方法是将列表或字典理解与切片结合在一起。如果您不需要订购商品(您只需要n个随机对),则可以使用如下的字典理解:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

通常,这样的理解总是比等效的“ for y中的x”循环要快。另外,通过使用.keys()创建字典关键字列表并对该列表进行切片,可以避免在构建新字典时“触摸”任何不必要的关键字。

如果不需要键(仅值),则可以使用列表推导:

first2vals = [v for v in mydict.values()[:2]]

如果您需要根据其键对值进行排序,那么麻烦就不多了:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

或者,如果您还需要按键:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}

2
如果您要选择N个许多key:value对作为字典,而不是列表,则这是一个更好的解决方案
fermat4214

1
@ fermat4214如果我在运行任何这些命令时都打印出整个词典,是否有问题?
泰德·泰勒

如果您不需要对字典进行排序,而只需要前两个元素,则list(mydict)[:2]就是浪费。如果字典中有100万个kv对,该怎么办?将整个内容转换为列表非常昂贵。Mark Byers的解决方案要好得多。
JJ

这应该是解决方案!
Guenter

14

Python的dict不排序,因此要求“前N个”键毫无意义。

collections.OrderedDict如果您需要,可以使用该课程。您可以有效地获得其前四个要素

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.islice允许您懒惰地从任何迭代器中获取元素的一部分。如果您希望结果可重用,则需要将其转换为列表或类似内容,例如:

x = list(itertools.islice(d.items(), 0, 4))

看起来不懒。比`list(d.items())[:4]
花费2倍的时间

12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

基本上,将视图(dict_items)变成一个迭代器,然后使用next()对其进行迭代。


2
妙极了的答案,这是此页面上唯一对我有用且可读的答案。另外,我可以验证它是否可以在Python 3中使用,某些较旧的答案似乎并没有。
cdahms

7

在这里没有看到它。如果只需要从字典中提取某些元素,则不会在语法上排序,而是从语法上最简单。

n = 2
{key:value for key,value in d.items()[0:n]}

7
我尝试了您的代码,但出现此错误:TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (stocks是我的字典的名称)
Moondra

2
@Moondra-必须先转换为列表,然后才能浏览字典项目。上面的代码,如果{key:key的值,list(d.items())[0:n]}中的值,则行有效
Rajesh Mappu,

{A:N代表(A,N)in [x代表d.items()中的x [:4]}}
farid khafizov

5

要从python字典中获取前N个元素,可以使用以下代码行:

list(dictionaryName.items())[:N]

您可以将其更改为:

list(d.items())[:4]

3

参见PEP 0265有关对字典进行排序。然后使用前面提到的可迭代代码。

如果您需要更高效率的已排序键值对。使用不同的数据结构。也就是说,它保持排序顺序和键值关联。

例如

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]

3

在py3中,这可以解决问题

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a':3,'b':2,'c':3,'d':4}


2

只需使用zip添加答案,

{k: d[k] for k, _ in zip(d, range(n))}

1

这取决于您的情况下“最有效”的方法。

如果您只想要一个巨大词典的半随机样本foofoo.iteritems()并根据需要使用它并从中获取尽可能多的值,那么这是一个懒惰的操作,可以避免创建键或项的显式列表。

如果您需要先对键进行排序,则无法使用keys = foo.keys(); keys.sort()sorted(foo.iterkeys())来构建键的显式列表。然后对第一个N进行切片或迭代keys

顺便说一句,您为什么关心“有效”方式?您是否对程序进行了简介?如果您没有这样做,请首先使用明显易于理解的方法。它很有可能在不成为瓶颈的情况下做得很好。


这是一个金融程序的应用程序,我试图尽可能高效地构建每一行代码。我没有介绍该程序,并同意这可能不会成为瓶颈,但是我想默认情况下要求有效的解决方案。谢谢回复。
詹森·斯特林珀2011年

0

您可以通过多种方法来实现。如果订单很重要,则可以执行以下操作:

for key in sorted(d.keys()):
  item = d.pop(key)

如果不需要订购,可以执行以下操作:

for i in range(4):
  item = d.popitem()

在第一个代码段中,您可能应该调用它value而不是item为了清楚起见。
2011年

0

字典没有顺序,因此在选择前N个键值对之前,先对其进行排序。

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

现在,我们可以使用以下方法结构来检索前N个元素:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

要获得前2个元素,则只需使用以下结构:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)

0

对于Python 3及更高版本,要选择前n对

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}

0

考虑一个命令

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice可以解决问题:)希望能有所帮助!


0

这可能不是很优雅,但是对我有用:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs

0

我已经尝试了上面的一些答案,并注意到其中一些是依赖于版本的,并且在3.7版中不起作用。

我还注意到,自3.6起,所有字典均按插入项的顺序排序。

尽管从3.6版开始就对字典进行了排序,但是您希望使用有序结构的某些语句似乎不起作用。

最适合我的OP问题的答案。

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]

仅供参考,慢5倍lst = list(d.items())[:N]
BSalita
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.