case class E(timestamp: Long, value: Double)
我有一个实例E列表。列表中的元素按时间戳排序。我想将具有0值的元素块分组到子列表中并删除非零值。例如,
val xs = List(E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)
其中E2, E3, E4, E7, E8, E10
的值为0
result = List(List(E2, E3, E4), List(E7, E8), List(E10))
在Scala中执行此操作的最佳方法是什么?谢谢!
答案 0 :(得分:2)
这是一行(使用foldLeft +过滤器):
scala> val l = List(1, 0, 0, 0, 2, 3, 0, 0, 5, 6, 0)
l: List[Int] = List(1, 0, 0, 0, 2, 3, 0, 0, 5, 6, 0)
scala> (l ++ List(1)).foldLeft((List(List[Int]()), List[Int]()))((a, b) => if (b != 0) (a._1 +: a._2, Nil) else (a._1, a._2 +: b))._1.filter(_.nonEmpty)
res26: List[List[Int]] = List(List(0, 0, 0), List(0, 0), List(0))
更易阅读的版本:
def groupByPred[T](l: List[T], predicate: T => Boolean = (x: T) => x == 0) = {
case class Acc(perm: List[List[T]] = Nil, temp: List[T] = Nil)
val raw = l.foldLeft(Acc())((a, b) =>
if (!predicate(b)) Acc(a.perm :+ a.temp, Nil) else Acc(a.perm, a.temp :+ b))
(raw.perm :+ raw.temp).filter(_.nonEmpty)
}
请注意":+"连接需要O(n),所以最好在这里使用ListBuffer而不是List。
答案 1 :(得分:1)
这是一个通用的方法,可以为您提供所需的内容:
def splitBy[A](l: List[A])(pred: A => Boolean): List[List[A]] = {
l match {
case Nil => Nil
case _ =>
val res = l.dropWhile(a => !pred(a))
val (acc, r) = res.span(pred)
acc :: splitBy(r)(pred)
}
}
以下是我设置的一般示例:
val E1 = E(1, 1)
val E2 = E(2, 0)
val E3 = E(3, 0)
val E4 = E(4, 0)
val E5 = E(5, 1)
val E6 = E(6, 1)
val E7 = E(7, 0)
val E8 = E(8, 0)
val E9 = E(9, 1)
val E10 = E(10, 0)
val xs = List(E1, E2, E3, E4, E5, E6, E7, E8, E9, E10)
println(splitBy(xs)(_.value == 0.0))
//prints List(List(E(2,0.0), E(3,0.0), E(4,0.0)), List(E(7,0.0), E(8,0.0)), List(E(10,0.0)))
请注意,这基本上是列表中的foldRight
并且不是堆栈友好的,例如这会导致堆栈溢出println(splitBy(List.fill(10000)(xs).flatten)(_.value == 0.0))
。
这是一个堆栈安全版本:
@tailrec
def splitBy[A](l: List[A], accum:List[List[A]] = Nil)(pred: A => Boolean): List[List[A]] = {
l match {
case Nil => accum.reverse
case _ =>
val res = l.dropWhile(a => !pred(a))
val (acc, r) = res.span(pred)
splitBy(r, acc :: accum)(pred)
}
}
答案 2 :(得分:0)
以下是使用takeWhile
和dropWhile
的相当惯用的方法。
def subLists[A](xs: List[A], p: A => Boolean):List[List[A]] = xs match{
case List() => List()
case h::t => {
if(p(h)){
xs.takeWhile(p) :: subLists(xs.dropWhile(p), p)
}else{
subLists(t, p)
}
}
}
输出
scala> subLists(xs, isEZero) │
res6: List[List[E]] = List(List(E(3,0.0), E(4,0.0), E(5,0.0)), List(E(7,0.0), E(8,0.0)), List(E(10,0.0)))
要为后续人员复制/粘贴的代码/数据。
def isEZero(e:E) = e.value == 0.0
val E1 = E(1L, 1.0)
val E2 = E(2L, 1.0)
val E3 = E(3L, 0.0)
val E4 = E(4L, 0.0)
val E5 = E(5L, 0.0)
val E6 = E(6L, 1.0)
val E7 = E(7L, 0.0)
val E8 = E(8L, 0.0)
val E9 = E(9L, 1.0)
val E10 = E(10L, 0.0)
val xs = List(E1,E2,E3,E4,E5,E6,E7,E8,E9,E10)