Mic*_*fik 3 python list-comprehension
我一直在家写小Python程序来学习更多关于语言的知识.我试图理解的最新功能是List Comprehensions.我创建了一个小脚本,根据我过去换油的频率来估计我的汽车何时需要换油.在下面的代码片段中,oil_changes列出了我更换石油的里程数.
# Compute a list of the mileage differences between each oil change.
diffs = [j - i for i, j in zip(oil_changes[:-1], oil_changes[1:])]
# Use the average difference between oil changes to estimate the next change.
next_oil = oil_changes[-1] + sum(diffs) / len(diffs)
Run Code Online (Sandbox Code Playgroud)
代码产生了正确的答案(手动数学检查)但它感觉不到Pythonic.我在第一行做了很多不必要的原始列表复制吗?我觉得有更好的方法可以做到这一点,但我不知道它是什么.
试试这个:
assert len(oil_changes) >= 2
sum_of_diffs = oil_changes[-1] - oil_changes[0]
number_of_diffs = len(oil_changes) - 1
average_diff = sum_of_diffs / float(number_of_diffs)
Run Code Online (Sandbox Code Playgroud)
正如其他答案所指出的那样,除非您的oil_changes列表非常长,否则您不必担心.然而,作为"基于流"的计算的粉丝,我认为有趣的是指出itertools提供next_oil在O(1)空间中计算价值所需的所有工具(当然还有O(N)时间! - )no无论N有多大,也就是说len(next_oil).
izip本身是不够的,因为它只减少乘法常数,但留下你的空间需求为O(N).关键的思想,使这些需求降到O(1)是配对izip与tee-和避免空间列表理解,这将是O(N)反正,有利于良好的简单的老式循环- !).来了:
it = iter(oil_changes)
a, b = itertools.tee(it)
b.next()
thesum = 0
for thelen, (i, j) in enumerate(itertools.izip(a, b)):
thesum += j - i
last_one = j
next_oil = last_one + thesum / (thelen + 1)
Run Code Online (Sandbox Code Playgroud)
我们不是从列表中取出切片,而是在它上面放一个迭代器,开发它(制作两个独立可推进的克隆),然后前进一次克隆,b.tee取空间O(x)其中x是各种克隆前进之间的最大绝对差值; 在这里,两个克隆的进展最多只相差1,所以空间要求显然是O(1).
izip对这两个稍微歪斜的克隆迭代器进行一次一个"压缩",我们将它打扮enumerate成我们可以跟踪我们经历循环的次数,即我们迭代的迭代的长度on(我们需要在最终表达式中使用+1,因为enumerate从0开始! - ).我们用简单的方法计算总和+=,这对于数字来说很好(sum甚至更好,但它不会跟踪长度! - ).
在使用循环之后它很诱人last_one = a.next(),但是这不会起作用,因为a它实际上已经耗尽了 - izip从左到右推进它的参数迭代,所以它a在它实现b结束之前最后一次前进! - ).没关系,因为Python循环变量的范围不限于循环本身 - 在循环之后,j仍然具有最后通过b在izip放弃之前前进而提取的值(就像thelen仍然具有返回的最后一个计数值一样enumerate).我仍然在命名值last_one而不是j直接在最终表达式中使用,因为我认为它更清晰,更易读.
所以它是 - 我希望它是有益的! - ) - 虽然为了解决你这次提出的具体问题,但几乎可以肯定是过度杀伤.我们意大利人有一句古老的谚语 - "Impara l'Arte,e mettila da parte!"......"学习艺术,然后把它放在一边" - 我认为这在这里非常适用:学习是件好事先进而复杂的方法来解决非常困难的问题,以防万一你遇到它们,但是对于所有你需要在简单和普通问题的更常见的情况下寻求简单和直接的方法 - 不应用最有可能赢得的高级解决方案不需要! - )
| 归档时间: |
|
| 查看次数: |
535 次 |
| 最近记录: |