我想实现一个称为map的函数,该函数接收一个列表和一个函数,并产生将函数应用于输入列表的每个元素的结果。 到目前为止,我已经知道了:
{
"id": 129748,
"ns": "av",
"name": "Polarized"
},
{
"id": 129898,
"ns": "av",
"name": "False"
}
此代码可以正常工作,并且可以为我带来预期的结果,但是我不禁想到,有一种更优雅,更有效的方法不涉及使用def map(list: List[Int], function: (Int) => Int): List[Int] = {
def loop(list: List[Int], acc: List[Int]): List[Int] = {
list match {
case Nil => acc
case head :: tail => loop(list.tail, function(head) :: acc)
}
}
loop(list.reverse, Nil)
}
或其他非reverse
的列表方法或head
。
答案 0 :(得分:4)
只要滚动自己的纯功能 map
函数实现,而无需使用任何可变状态或内置的List
高阶函数< / em>,您做得很棒!不必reverse
列表似乎没有必要,但这是值得的,因为在列表之前添加前缀是非常有效的操作。
以及注释中建议的其他方法,您可以将acc
设为scala.collection.mutable.ListBuffer
(它支持有效的追加和前置操作),然后在完成后将其转换为列表。但是,转换过程与reverse
相比并没有很大的进步。
否则,您可以做一些次要的事情来改善map
功能:
map
。scala.annotation.tailrec
属性修饰。这样, Scala 编译器就会知道您的意图,如果无法优化该函数以使用尾部递归,则会发出错误。reverse
操作。它对 map 操作没有影响,但是例如,如果要编写 filter 操作,则反转可能较小的已过滤集合的效率更高。元素。这是下面的样子:
import scala.annotation.tailrec
def map[A, B](list: List[A])(function: (A) => B): List[B] = {
@tailrec
def loop(rem: List[A], acc: List[B]): List[B] = rem match {
case Nil => acc.reverse
case head :: tail => loop(tail, function(head) :: acc)
}
loop(list, Nil)
}
答案 1 :(得分:3)
因为head :: tail
是解构和重建List
的最有效方法,所以您所做的是一个非常普通的模式。 .reverse
很不幸,但通常会导致轻微的性能损失。
如评论中所述,map
也可以通过其他标准库方法来实现。这是通过foldRight
完成的:
def map(list :List[Int], function :Int => Int) :List[Int] =
list.foldRight(List.empty[Int])(function(_) :: _)