将Scala列表中的最后一个元素进行转换

3
6个回答

9
另一种类似的方法是:
l match{
  case Nil            => Nil
  case xs :+ y => xs :+ change(y)
}

2
您可以像这样做:

您可以像这样做:

val l2 = l1.dropRight(1) :+ change(l1.last)

话虽如此,但是请记住,列表是一个很好的数据结构,可以访问其头部(并操作其尾部),但是对于随机和直接访问来说非常低效。如果您需要访问最后一个元素,则使用直接访问结构,例如数组或向量,将更加高效。


1
这会对同一个列表进行两次迭代。 - vvg
1
实际上是3倍,因为插入到最后一个位置。我已经强调使用列表来做这个不是最优的选择。 - hasumedic

1
也许你正在寻找这样的东西: list.init :+ changes(list.last) 但是@mfirry提供的示例将更快,更安全。 为了获得更好的性能,您可以使用Vector而不是List

0

稍微通用一些的版本(仍然只接受列表作为输入)

  def mutateLast[A, R](l: List[A])(f: A => A)(implicit cb: CanBuildFrom[List[A], A, R]): R = {
    val builder = cb(l)

    @annotation.tailrec
    def loop(l: List[A]): R = l match {
      case Nil => builder.result()
      case h :: Nil =>
        builder += f(h)
        builder.result()
      case h :: t =>
        builder += h
        loop(t)
    }

    loop(l)
  }

  val l = List(1, 2, 3)
  val mutated = mutateLast(l)(x => x * 2)
  println(mutated)

}


0

基于链接问题中被接受的答案进行改编的版本,只需迭代两次列表。显而易见:)

val l2 = (l1.reverse match{
  case Nil   => Nil
  case x::xs => change(x)::xs
}).reverse

如果你有一个不可变的列表,那么最好的方法就是迭代两次。第一次找到最后一个元素,第二次用更改后的元素替换它。


-1

必须承认,这个 List 的代码相当低效。 splitAt 函数的复杂度为 O(n)... 但是同样的复杂度也适用于 .last 函数。假设要获得更好的性能,应该使用一些索引集合而不是列表。

  l.splitAt(l.size - 1) match {
    case (l1, l2) => l1 ::: l2.map(modify(_))
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接