Python等效的Scheme / Lisp CAR和CDR函数

时间:2018-04-29 02:27:54

标签: python higher-order-functions

我目前正在尝试在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]]

这是实现此功能的有效方式吗?我错过了某种内置功能吗?提前谢谢!

1 个答案:

答案 0 :(得分:2)

"类似于Lisp CDR功能"是微不足道的:

acc[1:]

这将比你的尝试快得多,但只是一个常数因素。

但是,首先要做到这一点并没有多大意义。 CDR的重点在于,当您的列表是存储在CONS单元格中的链表时,从一个单元格到它的尾部是一个单一的机器语言操作。但是对于数组(这是Python列出的那些),acc[1:] - 或者你试图编写的更复杂的东西,或者实际上任何可能的实现 - 分配一个大小为N-1的全新数组并在N上复制1个值。

反复这样做的效率成本(在一种期望它几乎免费的算法中)将是如此巨大,以至于使用acc[1:]的恒定因子加速不太可能接近足够的改进使其可以接受。

大多数快速使用CDR的算法在使用这种切片时会变慢,并且大多数快速使用这种切片的算法对CDR来说都会很慢。这就是为什么我们首先拥有多个数据结构的原因:因为它们适用于不同的事物。

如果你想知道在阵列上折叠/缩小的最有效方法 - 就像functools.reduce(以及像toolz这样的库提供的变体)的方式一样:只是迭代。

只是迭代还有另一个巨大的优势。 Python并不只是有列表,它有一个名为iterables的抽象,它包括迭代器和其他可以懒惰地生成内容的类型。如果你向前折叠,你可以利用这种懒惰。 (向后折叠当然会采用线性空间,无论是显式还是堆叠 - 但它仍然比二次复制更好。)忽略这一事实会使目的失败。