给定一系列元素和一个谓词p
,我想生成一系列序列,这样,在每个子序列中,要么所有元素都满足p
,要么序列的长度为{{1 }}。另外,在结果上调用1
会让我恢复原始序列(因此不会重新排序元素)。
例如,给定:
.flatten
我希望val l = List(2, 4, -6, 3, 1, 8, 7, 10, 0)
val p = (i : Int) => i % 2 == 0
能够制作:
magic(l,p)
我知道List(List(2, 4, -6), List(3), List(1), List(8), List(7), List(10, 0))
,但该方法在第一次遇到不满足.span
的值并且只返回一对时停止。
以下是候选实施方案。它做我想要的,但是,好吧,让我们想哭。我希望有人能够提出一些更具惯用性的东西。
p
(请注意,我并不特别关心保留def magic[T](elems : Seq[T], p : T=>Boolean) : Seq[Seq[T]] = {
val loop = elems.foldLeft[(Boolean,Seq[Seq[T]])]((false,Seq.empty)) { (pr,e) =>
val (lastOK,s) = pr
if(lastOK && p(e)) {
(true, s.init :+ (s.last :+ e))
} else {
(p(e), s :+ Seq(e))
}
}
loop._2
}
的实际类型。)
答案 0 :(得分:3)
对于此任务,您可以使用takeWhile
和drop
结合匹配递归的小模式:
def magic[T](elems : Seq[T], p : T=>Boolean) : Seq[Seq[T]] = {
def magic(elems: Seq[T], result: Seq[Seq[T]]): Seq[Seq[T]] = elems.takeWhile(p) match {
// if elems is Nil, we have a result
case Nil if elems.isEmpty => result
// if it's not, but we don't get any values from takeWhile, we take a single elem
case Nil => magic(elems.tail, result :+ Seq(elems.head))
// takeWhile gave us something, so we add it to the result
// and drop as many elements from elems, as takeWhile gave us
case xs => magic(elems.drop(xs.size), result :+ xs)
}
magic(elems, Seq())
}
答案 1 :(得分:3)
我不会使用foldLeft
。如果头部与谓词不匹配,它只是span
的简单递归和特殊规则:
def magic[T](elems: Seq[T], p: T => Boolean): Seq[Seq[T]] =
elems match {
case Seq() => Seq()
case Seq(head, tail @ _*) if !p(head) => Seq(head) +: magic(tail, p)
case xs =>
val (prefix, rest) = xs span p
prefix +: magic(rest, p)
}
你也可以进行尾递归,但是如果你在前置(合理的话),你需要记住反转输出:
def magic[T](elems: Seq[T], p: T => Boolean): Seq[Seq[T]] = {
def iter(elems: Seq[T], out: Seq[Seq[T]]) : Seq[Seq[T]] =
elems match {
case Seq() => out.reverse
case Seq(head, tail @ _*) if !p(head) => iter(tail, Seq(head) +: out)
case xs =>
val (prefix, rest) = xs span p
iter(rest, prefix +: out)
}
iter(elems, Seq())
}
答案 2 :(得分:0)
另一种使用折叠的解决方案:
def magicFilter[T](seq: Seq[T], p: T => Boolean): Seq[Seq[T]] = {
val (filtered, current) = (seq foldLeft (Seq[Seq[T]](), Seq[T]())) {
case ((filtered, current), element) if p(element) => (filtered, current :+ element)
case ((filtered, current), element) if !current.isEmpty => (filtered :+ current :+ Seq(element), Seq())
case ((filtered, current), element) => (filtered :+ Seq(element), Seq())
}
if (!current.isEmpty) filtered :+ current else filtered
}