2011-01-21 16 views

Respuesta

15

Este es el truco que normalmente utilizo:

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 es, por lo general abstracto sobre el tipo de colección y optimizar la recursión de cola también, pero quería mantener la sencilla respuesta.

+2

Agradable. Pero, ¿no sería esto lo suficientemente común como para garantizar su propia función de biblioteca? –

+0

Sin argumentos, sin duda surge en preguntas más de una vez ... –

+0

@KevinWright "optimizar con recursividad de cola también" -> ¿Cómo lo harías? –

8
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) 
6
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) 
+0

¿Funcionaría alguno de los enfoques con los valores de NaN? Estoy tratando de averiguar si veo n valores consecutivos Double.NaN en un Vector.Mirando las soluciones publicadas aquí, parece que esto no es nada, voy a venir yo mismo. – TomTom101

+0

Los valores de NaN requerirían un manejo especial, de hecho. Tal vez podría envolver el 'Int's en' Opción [Int] ', y convertir el' NaN's a 'None's. Entonces las soluciones habituales basadas en la igualdad funcionarían. O podrías escribir tu propia función de igualdad. – Landei

8

Maldita Rex Kerr, para escribir la respuesta que iría a. Dado que no existen diferencias de estilo de menor importancia, aquí está mi tomar:

list.tail.foldLeft(List(list take 1)) { 
    case (acc @ (lst @ hd :: _) :: tl, el) => 
     if (el == hd) (el :: lst) :: tl 
     else (el :: Nil) :: acc 
} 

Dado que los elementos son idénticos, no me molesté revertir las sublistas.

+0

¿Puede por favor explicar (o señalarme algún enlace) caso (acc @ (lst @ hd :: _). Nunca he visto tal sintaxis antes. Gracias de antemano – gashu

+1

@gashu En un patrón coincidente, 'x @ y' significa que a 'x' se le asignará lo que sea _matched_ por' y'. Entonces, por ejemplo, 'x @ _ :: _' asignará a xa una lista no vacía (es decir, una lista con una cabecera y una cola) , como corresponde a '_ :: _'). Así que' acc', arriba, es la lista completa, y 'lst' es el encabezado de la lista. –

+0

@ daniel-c-sobral así que tales expresiones solo se usan en patrones haciendo coincidir, o en otro contexto, significan algo diferente? – gashu

5

Tengo estas implementaciones de trabajar en métodos de colecciones. 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) 
} 

[Edit: olvidar otras personas no sabrán las partes internas. Este código está escrito desde el interior de TraversableLike, para que no se ejecute fuera de la caja]

0

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 
+9

Eso agrupará todos los elementos idénticos, no solo de forma secuencial. –

2

he aquí una solución recursiva de cola inspirado 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 
    } 
} 
Cuestiones relacionadas