当前位置: 首页 > news >正文

Python Cookbook-5.6 以随机顺序处理列表的元素

任务

你想以随机的顺序处理一个很长的列表。

解决方案

一如既往的,在 Python 中最简单的方法常常是最好的。如果我们允许修改输入列表中的元素的顺序,那么下面的函数就是最简单和最快的:

def process_all_in_random_order(data,process):
	#首先,将整个列表置于随机顺序
	random.shuffle(data)
	#然后,根据正常顺序访问
	for elem in data:process(elem)

如果我们需要保证输入列表不变,或者输人列表可能是其他可选代对象而不是列表可以在函数主体开头加上一条赋值语句data = list(data)。

讨论

虽然过度关心速度常常是个错误,但我们也不能忽略不同算法的性能。假设我们必须以随机顺序处理一个不重复的长列表的元素。第一个想法可能会是这样:我们可以反复地、随机地挑出元素(通过random.choice 函数),并将原列表中被挑选的元素删除以避免重复挑选:

import random
def process_random_removing(data,process):
	while data:
		elem = random.choice(data)
		data.remove(elem)
		process(elem)

然而,这个函数慢得可怕,即使输入列表只有几百个元素。每个data.remove 调用都会线性地搜索整个列表以获取要删除的元素。由于第n步的时间消耗是O(n),因此整个处理过程的消耗时间是〇(n2),正比于列表长度的平方(而且要乘上一个很大的常数)。

对第一个想法的一点提高是将注意力集中在获取随机索引上,并使用列表的pop方法来同时获取和删除元素,这种更底层的方式避免了较大的消耗,尤其是在某些情况下比如要被挑选的元素位于列表的最后,或者使用的压根不是列表,而是字典或集合。若我们面对的是字典或集合,一条思路是寄希望于使用dict的popitem方法(或者sets.Set 或 Python 2.4 内建类型 set 的等价的 pop 方法),看上去这个函数好像被设计为随机选择一个元素并删除之,但是,小心上当。

dict.popitem 的文档指出,它返回并删除字典中的任意一个元素,但这和真正的随机元素还差得很远。看看这个:

>>> d = dict(enumerate('ciao'))
>>> while d: print d.popitem()

你可能会很吃惊,在大多数的 Python 实现中,这个代码片段都将以看上去不太随机的一句话,如果需要 Python 中的方式打印d的元素,通常是(0,‘c’),然后(1,‘i’),等等。伪随机行为,需要的是标准库的randompopitem 模块。

如果你考虑使用字典而不是列表,那么你肯定在“Python 式思维”的路上又前进了一步,虽然字典并不会针对这个特定问题提供什么性能优势。但相比于选择正确的数据结构,更具有Python 风格的方式是:总是利用标准库。Python标准库是个庞大、丰富的库,塞满了各种有用的、强健的、快速的函数和类,可满足各种应用的需求。在这个前提下,最关键的一点是要意识到,想要以随机的顺序访问序列,最简单的方法是首先将序列转化成随机的顺序(也被称为对序列洗牌,是对扑克洗牌的类比),然后再线性的访问洗完牌的序列即可。random.shufle 函数就可以执行洗牌操作,本节解决方案正是利用了这个函数。

实际性能总是需要测试,而不是猜测出来的,那也正是标准库模块 timeit 存在的原因。使用一个空的 process 函数和一个长度为1000的列表作为data,process_all in_randomorder 能比 process random removing快大约10倍;对于长度为2000 的列表,这个比例变成了 20。如果提升仅仅是 25%,或者是一个常数因子2,那么通常这个性能差异是可以忽略的,因为这不会对你的整体应用产生什么性能影响,但如果算法慢了10或20倍,情况就不同了。这种可怕的低效会成为整个程序的瓶颈。当我们谈到(n2)和O(n)的行为对比时,问题的严重性根本无法忽视:对于这两种大 0的行为,随着输入数据的增长,它们消耗时间的差异可以无限地递增下去。

相关文章:

  • 配环境的经验
  • 盈亏平衡IRR
  • LLM Agents的历史、现状与未来趋势
  • 【Netty4核心原理④】【简单实现 Tomcat 和 RPC框架功能】
  • GaussDB回调机制深度实践:从事件驱动到系统集成
  • 36.[前端开发-JavaScript高级]Day01-this和箭头函数的使用
  • java的文件输入输出流(FileInputStream、FileOutputStream、FileReader、FileWriter)
  • redis中的set
  • pikachu靶场搭建教程,csfr实操
  • AI日报 - 2025年4月8日
  • 关于动态规划
  • 解决 Lettuce 在 Redis 集群模式下的故障转移问题
  • 基于人工智能的医学影像关联分析:利用潜在空间几何混杂因素校正法|文献速递-深度学习医疗AI最新文献
  • WEB安全--内网渗透--利用Net-NTLMv2 Hash
  • 使用Scade实现神经网络算法
  • CMake 字段使用
  • 蓝桥杯真题--最长子序列 and 2023
  • SQL:Primary Key(主键)和Foreign Key(外键)
  • cpp自学 day20(文件操作)
  • 关于sqlsugar实体多层List映射的问题
  • 沈阳专业制作网站/新闻热点
  • 有专门做ppt的网站有哪些/国内永久免费云服务器
  • 2019年云南建设银行招聘网站/网络营销的作用
  • 高端网站建设机构/常用的网络营销方式
  • 网站如何被收录/游戏优化是什么意思
  • 做招聘的网站/360排名优化工具