统计字典列表中的条目:for循环与用map(itemgetter)的列表推导式
在我写的一个Python程序中,我比较了使用for
循环和增加变量的方法,和用map(itemgetter)
以及len()
来计算列表中字典的条目数量。发现这两种方法所花的时间是一样的。我是不是做错了什么,或者有没有更好的方法呢?
这里有一个大大简化和缩短的数据结构:
list = [
{'key1': True, 'dontcare': False, 'ignoreme': False, 'key2': True, 'filenotfound': 'biscuits and gravy'},
{'key1': False, 'dontcare': False, 'ignoreme': False, 'key2': True, 'filenotfound': 'peaches and cream'},
{'key1': True, 'dontcare': False, 'ignoreme': False, 'key2': False, 'filenotfound': 'Abbott and Costello'},
{'key1': False, 'dontcare': False, 'ignoreme': True, 'key2': False, 'filenotfound': 'over and under'},
{'key1': True, 'dontcare': True, 'ignoreme': False, 'key2': True, 'filenotfound': 'Scotch and... well... neat, thanks'}
]
这是for
循环的版本:
#!/usr/bin/env python
# Python 2.6
# count the entries where key1 is True
# keep a separate count for the subset that also have key2 True
key1 = key2 = 0
for dictionary in list:
if dictionary["key1"]:
key1 += 1
if dictionary["key2"]:
key2 += 1
print "Counts: key1: " + str(key1) + ", subset key2: " + str(key2)
上面数据的输出结果:
Counts: key1: 3, subset key2: 2
这是另一种可能更符合Python风格的版本:
#!/usr/bin/env python
# Python 2.6
# count the entries where key1 is True
# keep a separate count for the subset that also have key2 True
from operator import itemgetter
KEY1 = 0
KEY2 = 1
getentries = itemgetter("key1", "key2")
entries = map(getentries, list)
key1 = len([x for x in entries if x[KEY1]])
key2 = len([x for x in entries if x[KEY1] and x[KEY2]])
print "Counts: key1: " + str(key1) + ", subset key2: " + str(key2)
上面数据的输出结果(和之前一样):
Counts: key1: 3, subset key2: 2
我有点惊讶这两种方法花费的时间是一样的。我在想有没有更快的方法。我肯定是忽略了什么简单的东西。
我考虑过的一个替代方案是把数据加载到数据库中,然后用SQL查询,但数据并不需要持久化,我还得考虑数据传输的开销等等,而且数据库并不总是可用。
我对数据的原始形式没有控制权。
上面的代码并不是为了追求风格。
1 个回答
12
我觉得你测量的方式不太对,因为你在测量代码的时候加了很多额外的负担(比如在顶层模块运行而不是放在函数里,或者进行输出)。把这两个代码片段放进名为 forloop
和 withmap
的函数里,然后在列表定义后面加一个 * 100
,这样可以让测量结果更有意义。在我这台慢慢的笔记本上,我发现:
$ py26 -mtimeit -s'import co' 'co.forloop()'
10000 loops, best of 3: 202 usec per loop
$ py26 -mtimeit -s'import co' 'co.withmap()'
10 loops, best of 3: 601 usec per loop
也就是说,所谓的“更符合 Python 风格”的方法 map
比普通的 for
方法慢了三倍——这说明它其实并不“更符合 Python 风格”;-)。
好的 Python 代码的标志是 简单,在我看来,这就是我自以为是地命名的...:
def thebest():
entries = [d['key2'] for d in list if d['key1']]
return len(entries), sum(entries)
经过测量,这种方法比 forloop
方法节省了 10% 到 20% 的时间。