Python:如何快速迭代字典列表

时间:2014-03-30 16:55:58

标签: python

我正在使用以下代码迭代字典列表以找到相应的键['5']并在找到时比较这些值。虽然它工作正常但我相信它可以改进以获得快速的性能。还有哪些其他方法可以达到相同的效果?

listA = [{1:'One', 2:'Two', 3:'Three'}, {4:'Four', 5:'Five', 6:'Six'}]
listB = [{4:'Four', 5:'Five', 6:'Six'}, {7:'Seven', 8:'Eight', 9:'Nine'}]

result=[]
for dictA in listA:
    if not 5 in dictA.keys(): continue
    for dictB in listB:
        if 5 in dictB.keys() and dictB[5]==dictA[5]:
            result.append(dictB[5])

6 个答案:

答案 0 :(得分:3)

快速检查还会显示4 in dictA4 in dictA.keys()更快。

答案 1 :(得分:2)

你必须分析代码以查看是否有改进,但它通常是朝着正确方向迈出的一步,使用内置函数进行过滤,而不是自己编写脚本,因为它会跳过解释您的过滤器样板代码。

for dictA in filter(lambda x : 4 in x, listA):
    for dictB in filter(lambda x : 5 in x, listB):
        if dictB[5]==dictA[5]:
            result.append(dictB[5])

此外,它使它更短,更具可读性,这与Python的Zen有关。你很熟悉Python程序的外观,因为很明显你似乎在尝试用Python编写类似C / Java的代码。

答案 2 :(得分:2)

首先:你没有使用listA的大部分内容;你关心的只是来自dictA[5]的价值观。因此,让我们在一个允许快速访问的数据结构中提取您关心的位:

interesting_vals = frozenset([dictA[5] for dictA in listA if 5 in dictA])

现在我们只需要检查listB。两种方法。首先是显而易见的:

result = [dictB[5] for dictB in listB
          if 5 in dictB and dictB[5] in interesting_vals]

或者如果您希望大多数dictB具有[5]元素,那么这可能会更快,因为它结合了访问和存在检查(将其与真实数据进行分析!):

NA = object()  # Will compare different to everything in interesting_vals
result = [dictB[5] for dictB in listB if dictB.get(5, NA) in interesting_vals]

如果列表很大,这个解决方案应该是O(len(listA)+ len(listB)),这比你原来的O(len(listA)* len(listB)好得多。)

请注意,我假设dictA [5]的值是可散列的并且具有与equals一致的散列 - 大多数内置类都是,但是一些自定义类可能无法正确实现散列。

答案 3 :(得分:1)

Oneliner:

%timeit filter(None, {item.get(5) for item in listA}.intersection(item.get(5) for item in listB))
100000 loops, best of 3: 8.59 us per loop

%%timeit
    ...: listA = [{1:'One', 2:'Two', 3:'Three'}, {4:'Four', 5:'Five', 6:'Six'}]
    ...: listB = [{4:'Four', 5:'Five', 6:'Six'}, {7:'Seven', 8:'Eight', 9:'Nine'}]
    ...: 
    ...: result=[]
    ...: for dictA in listA:
    ...:     if not 4 in dictA.keys(): continue
    ...:     for dictB in listB:
    ...:         if 5 in dictB.keys() and dictB[5]==dictA[5]:
    ...:             result.append(dictB[5])
    ...:             
100000 loops, best of 3: 11.9 us per loop

答案 4 :(得分:0)

result = [
    y[5]
    for x in listA
    if 5 in x
    for y in listB
    if 5 in y and x[5] == y[5]
]

答案 5 :(得分:0)

你应该总是测试速度,但是生成器表达式(或列表推导)应该比迭代更快:

result= []
A = (a for a in listA if 5 in a) 
for a in A:
    result.extend(b[5] for b in listB if (5 in b and a[5] == b[5]))

或尝试去实现:

import functools
fives = partial(filter, lambda x: 5 in x)
for a in fives(listA):
    result.extend(b[5] for fives(listB) if a[5] == b[5])