【发布时间】:2011-06-13 06:44:36
【问题描述】:
例如:
List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
我想去:
List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))
我假设有一个简单的 List 函数可以做到这一点,但我找不到它。
【问题讨论】:
标签: scala collections
例如:
List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
我想去:
List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))
我假设有一个简单的 List 函数可以做到这一点,但我找不到它。
【问题讨论】:
标签: scala collections
这是我通常使用的技巧:
def split[T](list: List[T]) : List[List[T]] = list match {
case Nil => Nil
case h::t => val segment = list takeWhile {h ==}
segment :: split(list drop segment.length)
}
其实...不是,我通常对集合类型进行抽象并使用尾递归进行优化,但希望答案保持简单。
【讨论】:
t 来自哪里?
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
这是另一种方式。
(List(xs.take(1)) /: xs.tail)((l,r) =>
if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
【讨论】:
list.foldRight(List[List[Int]]()){
(e, l) => l match {
case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
case _ => List(e) :: l
}
}
或者
list.zip(false :: list.sliding(2).collect{case List(a,b) => a == b}.toList)
.foldLeft(List[List[Int]]())((l,e) => if(e._2) (e._1 :: l.head) :: l.tail
else List(e._1) :: l ).reverse
[编辑]
//find the hidden way
//the beauty must be somewhere
//when we talk scala
def split(l: List[Int]): List[List[Int]] =
l.headOption.map{x => val (h,t)=l.span{x==}; h::split(t)}.getOrElse(Nil)
【讨论】:
Ints 包装在Option[Int] 中,并将NaNs 转换为Nones。然后通常基于平等的解决方案将起作用。或者您可以编写自己的相等函数。
该死的 Rex Kerr,写下我想要的答案。由于存在细微的风格差异,这是我的看法:
list.tail.foldLeft(List(list take 1)) {
case (acc @ (lst @ hd :: _) :: tl, el) =>
if (el == hd) (el :: lst) :: tl
else (el :: Nil) :: acc
}
由于元素相同,我没有费心反转子列表。
【讨论】:
x @ y 表示x 将被分配给y匹配的任何内容。因此,例如,x @ _ :: _ 将分配给 x 一个非空列表(即,与 _ :: _ 匹配的具有头部和尾部的列表)。所以上面的acc 是整个列表,lst 是列表的头部。
我在处理集合方法时有这些实现。最后,我签入了更简单的 inits 和 tails 实现,并省略了集群。每一种新方法,无论多么简单,最终都会征收一笔从外部很难看到的巨额税款。但这是我没有使用的实现。
import generic._
import scala.reflect.ClassManifest
import mutable.ListBuffer
import annotation.tailrec
import annotation.unchecked.{ uncheckedVariance => uV }
def inits: List[Repr] = repSequence(x => (x, x.init), Nil)
def tails: List[Repr] = repSequence(x => (x, x.tail), Nil)
def cluster[A1 >: A : Equiv]: List[Repr] =
repSequence(x => x.span(y => implicitly[Equiv[A1]].equiv(y, x.head)))
private def repSequence(
f: Traversable[A @uV] => (Traversable[A @uV], Traversable[A @uV]),
extras: Traversable[A @uV]*): List[Repr] = {
def mkRepr(xs: Traversable[A @uV]): Repr = newBuilder ++= xs result
val bb = new ListBuffer[Repr]
@tailrec def loop(xs: Repr): List[Repr] = {
val seq = toCollection(xs)
if (seq.isEmpty)
return (bb ++= (extras map mkRepr)).result
val (hd, tl) = f(seq)
bb += mkRepr(hd)
loop(mkRepr(tl))
}
loop(self.repr)
}
[编辑:我忘记其他人不会知道内部情况。这段代码是从 TraversableLike 内部编写的,所以它不会开箱即用。]
【讨论】:
这可能更简单:
val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values
【讨论】:
这是一个受@Kevin Wright 和@Landei 启发的尾递归解决方案:
@tailrec
def sliceEqual[A](s: Seq[A], acc: Seq[Seq[A]] = Seq()): Seq[Seq[A]] = {
s match {
case fst :: rest =>
val (l, r) = s.span(fst==)
sliceEqual(r, acc :+ l)
case Nil => acc
}
}
【讨论】:
这是一个稍微干净一点的:
def groupConsequtive[A](list: List[A]): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
(head :: t1) :: groupConsequtive(t2)
case _ => Nil
}
尾递归版本
@tailrec
def groupConsequtive[A](list: List[A], acc: List[List[A]] = Nil): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
groupConsequtive(t2, acc :+ (head :: t1))
case _ => acc
}
【讨论】: