为了
trait Item
case class TypeA(i: Int) extends Item
case class TypeB(i: Int) extends Item
考虑一个 Scala 列表,例如
val myList = List(TypeA(1), TypeB(11), TypeB(12),
TypeA(2), TypeB(21),
TypeA(3), TypeB(31))
目标是定义一个新的 slice
方法,该方法可以应用于 myList
并以谓词或条件作为参数;例如
myList.slice { x => x.isInstanceOf[TypeA] }
会交付
List(List(TypeA(1), TypeB(11), TypeB(12)),
List(TypeA(2), TypeB(21)),
List(TypeA(3), TypeB(31)))
在这个例子中,相同的结果将通过
实现myList.slice { case TypeA(x) => x < 10 }
非常感谢。
最佳答案
List
已经有一个 slice
方法 - 它采用开始索引和结束索引之间的元素子集。您正在寻找的是 span
方法的重复应用:
def span(p: (A) ⇒ Boolean): (List[A], List[A])
记录为:
Splits this list into a prefix/suffix pair according to a predicate.
Note: c span p is equivalent to (but possibly more efficient than) (c takeWhile p, c dropWhile p), provided the evaluation of the predicate p does not cause any side-effects.
returns: a pair consisting of the longest prefix of this list whose elements all satisfy p, and the rest of this list.
您可以通过将此方法与反向谓词重复使用来获得所需的内容,并使用额外的逻辑来确保返回的列表都不为空。
import annotation.tailrec
def multiSpan[A](xs: List[A])(splitOn: (A) => Boolean): List[List[A]] = {
@tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(xs, Nil).reverse
}
更新
根据原始帖子评论中的要求,这里有一个丰富列表而不是独立方法的版本:
implicit class AddMultispanToList[A](val list: List[A]) extends AnyVal {
def multiSpan(splitOn: (A) => Boolean): List[List[A]] = {
@tailrec
def loop(xs: List[A], acc: List[List[A]]) : List[List[A]] = xs match {
case Nil => acc
case x :: Nil => List(x) :: acc
case h :: t =>
val (pre,post) = t.span(!splitOn(_))
loop(post, (h :: pre) :: acc)
}
loop(list, Nil).reverse
}
}
用作:
myList.multiSpan(_.isInstanceOf[TypeA])
关于list - 如何扩展 Scala 列表以启用不是按显式位置而是按给定谓词/条件的切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21800041/