funciones - listas en scala
Función de lista Scala para agrupar elementos idénticos consecutivos (7)
Dado por ejemplo:
List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
Me gustaría llegar a:
List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))
Asumiría que hay una función de lista simple que hace esto, pero no puedo encontrarlo.
Este es el truco que normalmente uso:
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)
}
En realidad ... No lo es, suelo abstraer el tipo de colección y optimizar con recursividad de cola también, pero quería mantener la respuesta simple.
Maldición Rex Kerr, por escribir la respuesta que iría. Como hay pequeñas diferencias de estilo, esta es mi opinión:
list.tail.foldLeft(List(list take 1)) {
case (acc @ (lst @ hd :: _) :: tl, el) =>
if (el == hd) (el :: lst) :: tl
else (el :: Nil) :: acc
}
Como los elementos son idénticos, no me molesté en invertir las sublistas.
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
Aquí hay otra manera.
(List(xs.take(1)) /: xs.tail)((l,r) =>
if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
Tengo estas implementaciones de trabajar en métodos de cobranza. Al final, verifiqué implementaciones más simples de inits y colas y dejé fuera el clúster. Cada nuevo método, sin importar cuán simple sea, termina recabando un gran impuesto que es difícil de ver desde el exterior. Pero aquí está la implementación que no usé.
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)
}
[Editar: Se me olvida que otras personas no sabrán las partes internas. Este código está escrito desde dentro de TraversableLike, por lo que no se ejecutará fuera de la caja.]
list.foldRight(List[List[Int]]()){
(e, l) => l match {
case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
case _ => List(e) :: l
}
}
O
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
[Editar]
//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)
esto podría ser más simple:
val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values
Aquí hay una solución recursiva de la cola inspirada por @Kevin Wright y @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
}
}