Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有一种更具pythonic风格/更高效的方法来循环包含列表的字典,而不是使用for循环?_Python_Python 2.7_List_Loops_For Loop - Fatal编程技术网

是否有一种更具pythonic风格/更高效的方法来循环包含列表的字典,而不是使用for循环?

是否有一种更具pythonic风格/更高效的方法来循环包含列表的字典,而不是使用for循环?,python,python-2.7,list,loops,for-loop,Python,Python 2.7,List,Loops,For Loop,在使用get以JSON格式从API提取信息之后,我现在尝试以高效的方式计算price的平均值 数据(API调用响应示例): 我通过以下代码成功地做到了这一点: len_sales = len(data["data"]["sales"]) total_p = 0 for i in range(0,len_sales): total_p += float(data["data"]["sales"][i]["price"]) average = total_p/len_sales print

在使用
get
JSON
格式从
API
提取信息之后,我现在尝试以高效的方式计算
price
的平均值

数据
(API调用响应示例):

我通过以下代码成功地做到了这一点:

len_sales = len(data["data"]["sales"])
total_p = 0 
for i in range(0,len_sales):
    total_p += float(data["data"]["sales"][i]["price"])
average = total_p/len_sales
print average
然而,由于检索到的
数据
字典很大,因此在显示输出之前似乎有相当长的等待时间


因此,我想知道是否有一种更有效和/或类似于python的方法可以在更短的时间内实现相同的结果。

首先,你不是在循环一个dict,而是在循环一个恰好位于dict内部的列表

第二,为列表中的每个值做一些事情本质上需要访问列表中的每个值;没有办法绕过线性成本

因此,唯一可用的是微优化,如果你的代码太慢,可能不会有太大的区别,快10%没有帮助,如果你的代码已经足够快,你不需要它,但偶尔需要它们

在这种情况下,几乎所有的微优化也使代码更具可读性和python风格,因此没有理由不这样做:


首先,您要访问
数据[“数据”][“销售”]
两次。这样做的性能成本可能可以忽略不计,但也会降低代码的可读性,因此,让我们来解决这个问题:

sales = data["data"]["sales"]
接下来,与在范围内(0,len_sales)为i循环
仅用于
sales[i]
,相比,仅循环
sales
,速度更快,可读性更强:

for sale in sales:
    total_p += float(sale["price"])
现在我们可以将这个循环转化为一种理解,它的效率稍微高一点(尽管添加一个生成器的成本部分抵消了这一点,您可能真的想要测试这个生成器):

…并将其直接传递给
sum

total_p = sum(float(sale["price"]) for sale in sales)
我们还可以使用Python附带的函数,而不是手动执行:

average = statistics.mean(float(sale["price"]) for sale in sales)
…除了您显然在使用Python2之外,所以您需要安装脱离PyPI的(官方的后端口仅可追溯到3.1;2.x版本已被放弃),所以让我们跳过这一部分

总而言之:

sales = data["data"]["sales"]
total = sum(float(sale["price"]) for sale in sales)
average = total / len(sales)

有几件事可能会有所帮助,如果这很重要,您肯定会希望使用
timeit
进行测试:

您可以使用获取
价格
项目。这意味着您的表达式现在只链接两个函数调用,这意味着您可以链接两个
map
调用:

total = sum(map(float, map(operator.itemgetter("price"), sales)))
对于不是来自Lisp背景的人来说,这可能比理解更难理解,但这肯定不可怕,而且可能会快一点


或者,对于中等规模的输入,构建临时列表有时是值得的。当然,您会浪费时间分配内存和复制数据,但是迭代列表要比迭代生成器快,所以真正确定的唯一方法是测试


还有一件事可能会有所不同,那就是将整个过程转化为一个函数。顶层的代码没有局部变量,只有全局变量,而且它们的查找速度较慢

如果您真的需要挤出最后几个百分点,有时甚至值得将全局函数和内置函数(如
float
)复制到局部函数中。当然,这对
map
(因为我们只访问了它们一次)没有帮助,但如果理解了这一点,可能会有帮助,因此我将演示如何执行:

def total_price(sales):
    _float = float
    pricegetter = operator.itemgetter("price")
    return sum(map(_float, map(pricegetter, sales)))

对代码进行基准测试的最佳方法是使用模块,或者,如果您使用的是IPython,则使用
%timeit
magic。其工作原理如下:

In [3]: %%timeit
... total_p = 0 
... for i in range(0,len_sales):
...     total_p += float(data["data"]["sales"][i]["price"])
10000 loops, best of 3: 28.4 µs per loop
In [4]: %timeit sum(float(sale["price"]) for sale in sales)
10000 loops, best of 3: 18.4 µs per loop
In [5]: %timeit sum(map(float, map(operator.itemgetter("price"), sales)))
100000 loops, best of 3: 16.9 µs per loop
In [6]: %timeit sum([float(sale["price"]) for sale in sales])
100000 loops, best of 3: 18.2 µs per loop
In [7]: %timeit total_price(sales)
100000 loops, best of 3: 17.2 µs per loop
因此,在我的笔记本电脑上,使用您的示例数据:

  • 直接在
    sales
    上循环并使用生成器表达式而不是语句大约快35%
  • 使用列表理解而不是genexpr比这快约1%
  • 使用
    map
    itemgetter
    代替genexpr大约快10%
  • 将其包装在函数中并缓存局部变量会使速度稍慢一些。(正如上面提到的,这并不奇怪,由于
    map
    ,我们只对每个名称进行了一次查找,所以我们只是增加了一点开销,可能带来了0的好处。)
总的来说,
sum(map(…map(…))
在我的笔记本电脑上是这个特定输入的最快版本

但当然,您需要在真实环境中使用真实输入重复此测试。当差异小到10%时,你不能仅仅假设细节会转移


还有一件事:如果您真的需要加快速度,通常最简单的方法是使用完全相同的代码,而不是使用通常的CPython解释器来运行它。重复上述一些测试:

In [4]: %timeit sum(float(sale["price"]) for sale in sales)
680 ns ± 19.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [5]: %timeit sum(map(float, map(operator.itemgetter("price"), sales)))
800 ns ± 24.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [6]: %timeit sum([float(sale["price"]) for sale in sales])
694 ns ± 24.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

现在生成器表达式版本是最快的,但更重要的是,这三个版本的速度大约是CPython中的20倍。2000%的改进比35%的改进要好得多。

您可以使用一个名为的库,找到销售列表的平均值。要获得销售清单,您可以进行列表理解-

prices = [float(v) for k, v in i.iteritems() for i in data["data"]["sales"] if k == "price"]
这会给你一份价格单。现在,您只需使用上面的库

mean(prices)
或者,你可以这样做-

mean_price = sum(prices) / len(prices)

你会得到平均价格。使用列表理解,您已经优化了代码。查看并阅读答案的最后一段

您能发布有效数据吗?非常感谢您的帮助!我真的很感谢你为这个答案投入的时间和细节:)祝你有一个愉快的一天。关于你最近的编辑,你有没有机会编辑这篇文章来展示“最快”的解决方案?谢谢:)太好了!谢谢,太棒了!
mean(prices)
mean_price = sum(prices) / len(prices)