列出scala中正数或负数的连续值
val a = List(1,1,2,3,-1,2,3,4,-1,-2,-3) //input
val z = List(List(1,2,3),List(-1),List(2,3,4),List(-1,-2,-3)) //expected
我尝试使用以下代码来显示列表。
val sd = a.span(_>=0) match {
case (left, Nil) => left
case (left, right) => left ++ ( right.filter(_>=0))
}
答案 0 :(得分:2)
恕我直言,始终使用 tail-recursive 算法来操纵 List 的最佳方法。
sealed trait Sign
object Sign {
final case object Positive extends Sign
final case object Negative extends Sign
final case object Neutral extends Sign
def of(i: Int): Sign =
if (i > 0) Positive
else if (i < 0) Negative
else Neutral
}
def extractBySign(sign: Sign)(list: List[Int]): (List[Int], List[Int]) = {
@annotation.tailrec
def loop(remaining: List[Int], acc: List[Int]): (List[Int], List[Int]) =
remaining match {
case Nil =>
acc.reverse -> Nil
case x :: xs if (Sign.of(x) == sign) =>
loop(remaining = xs, x :: acc)
case list =>
acc.reverse -> list
}
loop(remaining = list, acc = List.empty)
}
def splitBySign(list: List[Int]): List[List[Int]] = {
@annotation.tailrec
def loop(remaining: List[Int], acc: List[List[Int]]): List[List[Int]] =
remaining match {
case x :: xs =>
val sign = Sign.of(x)
val (list, newRemaining) = extractBySign(sign)(x :: xs)
loop(newRemaining, list :: acc)
case Nil =>
acc.reverse
}
loop(remaining = list, acc = List.empty)
}
答案 1 :(得分:2)
这是foldLeft
def consecutiveLists(as : List[Int]) : List[List[Int]] =
as.foldLeft(List[List[Int]](List[Int]())) ((a,b) => {
val index = a.size - 1
val currentList = a.last
if(b >= 0 && (currentList.isEmpty || currentList.last < 0)) {
a :+ List(b)
} else if(b >=0 && (currentList.isEmpty || currentList.last >= 0)) {
a.updated(index, currentList :+ b)
} else if(b < 0 && (currentList.isEmpty || currentList.last >=0)) {
a :+ List(b)
} else {
a.updated(index, currentList :+ b)
}
})
测试:
consecutiveLists(List(1,1,2,3,-1,2,3,4,-1,-2,-3))
consecutiveLists(List(-1,-2,1,1,2,3,-1,2,3,4,-1,-2,-3))
consecutiveLists(List(-1))
consecutiveLists(List(-1,1,-1,1,2,-1,-1))
res0: List[List[Int]] = List(List(), List(1, 1, 2, 3), List(-1), List(2, 3, 4), List(-1, -2, -3))
res1: List[List[Int]] = List(List(), List(-1, -2), List(1, 1, 2, 3), List(-1), List(2, 3, 4), List(-1, -2, -3))
res2: List[List[Int]] = List(List(), List(-1))
res3: List[List[Int]] = List(List(), List(-1), List(1), List(-1), List(1, 2), List(-1, -1))
注意:
结果将始终有一个空列表作为保护值。 drop(1)
可以摆脱这个问题
这四个条件可以简化为两个。我没有进一步简化它以显示基本逻辑:
如果当前值与符号相反,请查看最后一个列表 最后一个列表,创建新列表,否则只需将当前值附加到最后一个列表。有 可能还有其他方法来简化它。
List[List[Int]]
可能不是最佳的数据结构。 Array[List[Int]]
或Vector[List[Int]]
可能是更好的选择。编辑:这是简化版:
as.foldLeft(List[List[Int]](List[Int]())) ((a,b) => {
val index = a.size - 1
val currentList = a.last
if((b >= 0 && (currentList.isEmpty || currentList.last < 0)) ||
(b < 0 && (currentList.isEmpty || currentList.last >=0))) {
a :+ List(b)
} else {
a.updated(index, currentList :+ b)
}
})
编辑2 :这是另一种简化方法。我正在使用保证O(1)添加项目的队列。对于保留列表,我正在使用矢量,因为此列表既可以更新也可以插入。另外,通过确保fold entry参数从不为空,也删除了对空列表的检查。
import scala.collection.immutable.Queue
type QI = Queue[Int]
def consecutiveLists(as : List[Int]) : Vector[QI] =
if(as.isEmpty)
Vector.empty[QI]
else
as.drop(1).foldLeft(Vector[QI](Queue[Int](as.head))) ((a,b) => {
val currentList = a.last
if((b >= 0 && currentList.last < 0) ||
(b < 0 && currentList.last >=0)) {
a :+ Queue(b)
} else {
a.updated(a.size - 1, currentList :+ b)
}
})