在Python字典中找到非零值的平均值
在这个Python字典中,最快的方法来找出非零“表”值的平均数是什么呢?
d = {"a":{"pen":12,"table":23},"b":{"pen":12,"table":0},"c":{"pen":16,"table":54}}
我想到的是:
count = sum(1 for inner_dict in d if d[inner_dict]["table"] > 0)
total = sum([d[inner_dict]["table"] for inner_dict in d if d[inner_dict]["table"] > 0])
average = total/count
结果应该是(23+54)/2 = 38
3 个回答
2
只循环一次:
n, s = reduce(lambda acc,v: (acc[0]+1,acc[1]+v["table"]) if v["table"] else acc,
d.values(),
(0.,0.))
print n, s, s/n
产生:
2.0 77.0 38.5
3
因为你问的是最快的方式,这里有一些时间测试的结果。需要说明的是,我是在Windows 8上使用IPython和Python 3.3,运行的是i7-3770处理器。另外,顺便提一下,在Python 2.x中不要用/
来做除法,因为那样会进行整数除法。可以用float(a)/b
,或者在文件顶部加上from __future__ import division
。
d = {"a": {"pen": 12, "table": 23},
"b": {"pen": 12, "table": 0},
"c": {"pen": 16, "table": 54}}
def method0(): # Your method
count = sum(1 for inner_dict in d if d[inner_dict]["table"] > 0)
total = sum([d[inner_dict]["table"] for inner_dict in d if d[inner_dict]["table"] > 0])
average = total/count
def method1():
count = 0
total = 0
for a in d.values():
val = a['table']
if val > 0:
count += 1
total += val
average = total/ count
def method2(): # user3684792's/Padraic Cunningham's method
filtered = [d[i]["table"] for i in d if d[i]["table"] > 0]
average = sum(filtered)/len(filtered)
# from functools import reduce # If using Python 3
def method3(): # Sylvain Leroux's method
n, s = reduce(lambda acc,v: (acc[0]+1,acc[1]+v["table"]) if v["table"] else acc,
d.values(),
(0, 0))
average = s/n
%timeit method0()
# 10000 loops, best of 3: 23.9 us per loop
%timeit method1()
# 1000000 loops, best of 3: 756 ns per loop
%timeit method2()
# 10000 loops, best of 3: 22.5 us per loop
%timeit method3()
# 1000000 loops, best of 3: 1.29 us per loop
初步结论:使用for循环和简单的加法(method1
)比任何列表推导的方法都要快。
这基本上是你可以预期的结果。注意,方法1和方法3只遍历数据一次,边走边收集数据。而方法0和方法2则需要多遍历几次,先过滤出想要的条目,然后再进行求和。
3
filtered = [d[i]["table"] for i in d if d[i]["table"]<>0]
avg = sum(filtered)/len(filtered)
其实不需要 <>0 这个东西。