结果列表的元素应在参数的元素之间交替。假设两个参数的长度相同。
我的代码如下
val finalString = new ListBuffer[Int]
val buff2= new ListBuffer[Int]
def alternate(xs:List[Int], ys:List[Int]):List[Int] = {
while (xs.nonEmpty) {
finalString += xs.head + ys.head
alternate(xs.tail,ys.tail)
}
return finalString.toList
}
alternate(列表(1、3、5),列表(2、4、6))=列表(1、2、3、4、6)
就输出而言,我没有任何输出。该程序仍在运行,无法执行。
答案 0 :(得分:4)
到目前为止,建议的递归解决方案存在一些问题(包括您的递归解决方案,如果您将while
替换为if
的话,这实际上是可行的):追加到列表末尾是线性操作,使整个事情都是二次的(也取列表的.length
,以及按索引访问元素),不要那样做;另外,如果列表很长,则递归可能会在堆栈上占用很多空间,因此您应该尽可能使用tail递归。
这是一个没有这两个问题的解决方案:它通过向列表中添加前置元素(恒定时间操作)而不是附加它们,来向后构建输出,并在结束。它也是尾递归的:递归调用是函数中的最后一个操作,它允许编译器将其转换为循环,因此无论列表大小如何,它都将仅使用单个堆栈框架执行。
@tailrec
def alternate(
a: List[Int],
b: List[Int],
result: List[Int] = Nil
): List[Int] = (a,b) match {
case (Nil, _) | (_, Nil) => result.reversed
case (ah :: at, bh :: bt) => alternate(at, bt, bh :: ah :: result)
}
(如果列表的长度不同,则最短的列表结束时整个过程将停止,而较长的列表中的所有内容将被丢弃。您可能需要修改第一个case
(将其拆分为两个,也许)如果您想要改变行为)。
顺便说一句,您自己的解决方案实际上比这里的大多数建议更好:它实际上是尾递归的(或者,如果在else
之后添加if
,则可以将其设为尾递归,现在为while
),并附加到ListBuffer
上实际上并不比List
差。但是使用可变状态通常在Scala中被认为是“代码异味”,应避免使用(这是使用递归而不是循环的主要思想之一)。
答案 1 :(得分:2)
条件xs.nonEmpty
始终为真,因此您有无限的while
循环。
也许您是说if
而不是while
。
答案 2 :(得分:2)
更像Scala式的方法是:
def alternate(xs: List[Int], ys: List[Int]): List[Int] = {
xs.zip(ys).flatMap{case (x, y) => List(x, y)}
}
alternate(List(1,3,5), List(2,4,6))
// List(1, 2, 3, 4, 5, 6)
答案 3 :(得分:1)
使用match
def alternate[T](a: List[T], b: List[T]): List[T] =
(a, b) match {
case (h1::t1, h2::t2) =>
h1 +: h2 +: alternate(t1, t2)
case _ =>
a ++ b
}
这可能会更清晰,但会更加清晰。
更新
这是更有效的解决方案:
def alternate[T](a: List[T], b: List[T]): List[T] = {
@annotation.tailrec
def loop(a: List[T], b: List[T], res: List[T]): List[T] =
(a, b) match {
case (h1 :: t1, h2 :: t2) =>
loop(t1, t2, h2 +: h1 +: res)
case _ =>
a ++ b ++ res.reverse
}
loop(a, b, Nil)
}
这保留了原始函数签名,但使用的是内部函数,该函数是算法的高效尾递归实现。
答案 4 :(得分:0)
您正在从方法外部访问变量,这很糟糕。我建议如下所示:
object Main extends App {
val l1 = List(1, 3, 5)
val l2 = List(2, 4, 6)
def alternate[A](l1: List[A], l2: List[A]): List[A] = {
if (l1.isEmpty || l2.isEmpty) List()
else List(l1.head,l2.head) ++ alternate(l1.tail, l2.tail)
}
println(alternate(l1, l2))
}
仍然是递归的,但是没有从方法外部访问状态。
答案 5 :(得分:-1)
假设两个列表的长度相同,则可以使用ListBuffer
来构建备用列表。 alternate
是一个纯函数:
import scala.collection.mutable.ListBuffer
object Alternate extends App {
def alternate[T](xs: List[T], ys: List[T]): List[T] = {
val buffer = new ListBuffer[T]
for ((x, y) <- xs.zip(ys)) {
buffer += x
buffer += y
}
buffer.toList
}
alternate(List(1, 3, 5), List(2, 4, 6)).foreach(println)
}