我看到Scala标准库错过了获取集合中对象范围的方法,它满足谓词:
def <???>(p: A => Boolean): List[List[A]] = {
val buf = collection.mutable.ListBuffer[List[A]]()
var elems = this.dropWhile(e => !p(e))
while (elems.nonEmpty) {
buf += elems.takeWhile(p)
elems = elems.dropWhile(e => !p(e))
}
buf.toList
}
这种方法有什么好名字?我的实施是否足够好?
答案 0 :(得分:7)
我选择 chunkWith 或 chunkBy
至于你的实现,我认为这是为了递归!看看你是否可以填写这个
@tailrec def chunkBy[A](l: List[A], acc: List[List[A]] = Nil)(p: A => Boolean): List[List[A]] = l match {
case Nil => acc
case l =>
val next = l dropWhile !p
val (chunk, rest) = next span p
chunkBy(rest, chunk :: acc)(p)
}
为什么递归?理解算法要容易得多,并且更容易没有错误(假设没有变量)。
用于否定谓词的语法!p是通过隐式转换实现的
implicit def PredicateW[A](p: A => Boolean) = new {
def unary_! : A => Boolean = a => !p(a)
}
我通常会保留它,因为它非常有用
答案 1 :(得分:2)
怎么样:
def chunkBy[K](f: A => K): Map[K, List[List[A]]] = ...
与groupBy
类似,但将连续的块保持为块状。
使用此功能,您可以xs.chunkBy(p)(true)
获得所需内容。
答案 2 :(得分:2)
您可能想要将其称为splitWith
,因为split
是一个或多或少的字符串操作,它与splitAt
类似。
顺便提一下,这是一个非常紧凑的实现(虽然它做了很多不必要的工作,所以它不是一个很好的速度实现;你的很好):
def splitWith[A](xs: List[A])(p: A => Boolean) = {
(xs zip xs.scanLeft(1){ (i,x) => if (p(x) == ((i&1)==1)) i+1 else i }.tail).
filter(_._2 % 2 == 0).groupBy(_._2).toList.sortBy(_._1).map(_._2.map(_._1))
}
答案 3 :(得分:1)
只需稍微改进 oxbow 的代码,这样签名就更轻了
def chunkBy[A](xs: List[A])(p: A => Boolean): List[List[A]] = {
@tailrec
def recurse(todo: List[A], acc: List[List[A]]): List[List[A]] = todo match {
case Nil => acc
case _ =>
val next = todo dropWhile (!p(_))
val (chunk, rest) = next span p
recurse(rest, acc ::: List(chunk))
}
recurse(xs, Nil)
}