我目前正在尝试在Python中实现fold
/ reduce
,因为我不喜欢functools
中的版本。这自然涉及实现像Lisp CDR
函数之类的东西,因为Python似乎没有类似的东西。这就是我在想的尝试:
def tail(lat):
# all elements of list except first
acc = []
for i in range(1,len(lat)):
acc = acc + [lat[i]]
这是实现此功能的有效方式吗?我错过了某种内置功能吗?提前谢谢!
答案 0 :(得分:2)
"类似于Lisp CDR功能"是微不足道的:
acc[1:]
这将比你的尝试快得多,但只是一个常数因素。
但是,首先要做到这一点并没有多大意义。 CDR的重点在于,当您的列表是存储在CONS单元格中的链表时,从一个单元格到它的尾部是一个单一的机器语言操作。但是对于数组(这是Python列出的那些),acc[1:]
- 或者你试图编写的更复杂的东西,或者实际上任何可能的实现 - 分配一个大小为N-1的全新数组并在N上复制1个值。
反复这样做的效率成本(在一种期望它几乎免费的算法中)将是如此巨大,以至于使用acc[1:]
的恒定因子加速不太可能接近足够的改进使其可以接受。
大多数快速使用CDR的算法在使用这种切片时会变慢,并且大多数快速使用这种切片的算法对CDR来说都会很慢。这就是为什么我们首先拥有多个数据结构的原因:因为它们适用于不同的事物。
如果你想知道在阵列上折叠/缩小的最有效方法 - 就像functools.reduce
(以及像toolz
这样的库提供的变体)的方式一样:只是迭代。
只是迭代还有另一个巨大的优势。 Python并不只是有列表,它有一个名为iterables的抽象,它包括迭代器和其他可以懒惰地生成内容的类型。如果你向前折叠,你可以利用这种懒惰。 (向后折叠当然会采用线性空间,无论是显式还是堆叠 - 但它仍然比二次复制更好。)忽略这一事实会使目的失败。