热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

是否有更多pythonic/更有效的方法来循环包含列表的字典而不是使用for循环?

如何解决《是否有更多pythonic/更有效的方法来循环包含列表的字典而不是使用for循环?》经验,为你挑选了1个好方法。

使用后get从中提取信息APIJSON格式,我现在试图计算的平均price高效的方式.

data (来自API调用的示例响应):

...
{u'status': u'success', u'data': {u'context_id': u'2', u'app_id': u'123', u'sales': [{u'sold_at': 133, u'price': u'1.8500', u'hash_name': u'Xuan881', u'value': u'-1.00000'}, {u'sold_at': 139, u'price': u'2.6100', u'hash_name': u'Xuan881', u'value': u'-1.00000'},
... etc.

我已设法使用以下代码执行此操作:

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

但是,由于data检索到的字典大小很大,因此在显示输出之前似乎有相当多的等待时间.

因此,我想知道是否有更高效和/或pythonic的方式来实现相同的结果,但是在更短的时间内.



1> abarnert..:

首先,你没有循环通过一个字典,你正在循环一个碰巧在dict里面的列表.

其次,为列表中的每个值执行某些操作本身就需要访问列表中的每个值; 没有办法绕线性成本.

因此,唯一可用的是微优化,这可能不会有太大的区别 - 如果你的代码太慢,10%的速度没有帮助,如果你的代码已经足够快,你就不需要了它 - 但有时他们是需要的.

在这种情况下,几乎所有的微优化也使你的代码更具可读性和Pythonic,所以没有充分的理由这样做:


首先,你要访问data["data"]["sales"]两次.它的性能成本可能是微不足道的,但它也使你的代码可读性降低,所以让我们解决这个问题:

sales = data["data"]["sales"]

接下来,而不是for i in range(0, len_sales):仅仅使用循环sales[i],它更快 - 并且,再次,更可读 - 只是循环sales:

for sale in sales:
    total_p += float(sale["price"])

现在我们可以将这个循环变成一个理解,这稍微有点效率(虽然这部分取消了添加生成器的成本 - 你可能实际上想要测试这个):

prices = (float(sale["price"]) for sale in sales)

...并将其直接传递给sum:

total_p = sum(float(sale["price"]) for sale in sales)

我们也可以使用meanPython附带的函数而不是手动执行:

average = statistics.mean(float(sale["price"]) for sale in sales)

...除了你显然使用Python 2,所以你需要安装PyPI 的非官方backport(官方stats后端只返回3.1; 2.x版本被放弃),所以让我们跳过那部分.

把它们放在一起:

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

一些可能有用的东西- 如果重要的话,你肯定会想要测试timeit:

您可以使用operator.itemgetter获取该price项目.这意味着你的表达式现在只链接两个函数调用,这意味着你可以链接两个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)))

对代码进行基准测试的最佳方法是使用timeit模块 - 或者,如果您使用的是IPython,那就是%timeit魔术.其工作方式如下:

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%.

使用mapitemgetter代替genexpr的速度提高了约10%.

将它包装在函数中并缓存本地文件会使事情稍微变慢.(这并不奇怪 - 如上所述,我们只对每个名称进行了一次查找,这要归功于map,所以我们只需要增加一小部分开销就可以获得0的好处.)

总的来说,sum(map(…map(…)))在我的笔记本电脑上,这个特殊输入被禁食了.

但是你当然希望用真正的输入在你的真实环境中重复这个测试.当小到10%的差异很重要时,您不能只假设细节会转移.


还有一件事:如果你真的需要加快速度,通常最简单的方法是使用完全相同的代码并在PyPy中运行它而不是通常的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%的改善好很多.


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 1print过程procprint<data数据集名><选项>;*label指定打印输出标签noobs制定不显示观测序号*by变量名1< ... [详细]
  • des算法php,Des算法属于加密技术中的
    本文目录一览:1、des是什么算法2、80分求 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
  • 【原创】利用Python进行河流遥感处理的PyRIS软件开发
    今天开始着手改造pyris1.0.文章地址:https:doi.org10.1016J.ENVSOFT.2018.03.028Monegaglia,2 ... [详细]
  • http:blog.sina.com.cnsblog_491529d60100061h.html安装完SLED10后发现仍然有“热启动网络不通”的问题,原因是内核版本 ... [详细]
  • NN,NearestNeighbor,最近邻KNN,K-NearestNeighbor,K最近邻KNN分类的思路:分类的过程其实是直接将测试集的每一个图片和训练集中的所有图片进行比 ... [详细]
author-avatar
林佳煌8888
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有