what switch pattern generic comprehension scala collections pattern-matching

pattern - switch case in scala



Coincidencia de patrones de Scala en secuencias distintas de listas (6)

Tengo el siguiente código que opera recursivamente en cada elemento dentro de una lista

def doMatch(list: List[Int]): Unit = list match { case last :: Nil => println("Final element.") case head :: tail => println("Recursing..."); doMatch(tail) }

Ahora, ignorando que esta funcionalidad está disponible a través de filter () y foreach () , esto funciona bien. Sin embargo, si trato de cambiarlo para aceptar cualquier Seq [Int] , me encuentro con problemas:

  • Seq no tiene ::, pero sí tiene + :, que, como yo entiendo, es básicamente lo mismo. Si intento hacer coincidir en head +: tail, sin embargo, el compilador se queja de ''error: not found: value +:''
  • Nil es específico de List, y no estoy seguro de qué reemplazarlo. Voy a probar Seq () si alguna vez supero el problema anterior

Así es como creo que debería parecer el código, excepto que no funciona:

def doMatch(seq: Seq[Int]): Unit = seq match { case last +: Seq() => println("Final element.") case head +: tail => println("Recursing..."); doMatch(tail) }

Editar: ¡Tantas buenas respuestas! Estoy aceptando la respuesta de agilesteel ya que fue el primero que notó que :: no es un operador en mi ejemplo, sino una clase de caso y, por lo tanto, la diferencia.


A partir de marzo de 2012, esto funciona en 2.10+:

def doMatch(seq: Seq[Int]): Unit = seq match { case last +: Seq() => println("Final element.") case head +: tail => println("Recursing..."); doMatch(tail) } //> doMatch: (seq: Seq[Int])Unit doMatch(List(1, 2)) //> Recursing... //| Final element.

De manera más general, se agregaron dos objetos diferentes de cabeza / cola e inicio / última descomposición que añaden append / prepend para Seq en SeqExtractors :

List(1, 2) match { case init :+ last => last } //> res0: Int = 2 List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2) Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2 Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)


En realidad, puede definir un objeto para +: para hacer exactamente lo que está buscando:

object +: { def unapply[T](s: Seq[T]) = if(s.nonEmpty) Some(s.head, s.tail) else None } scala> val h +: t = Seq(1,2,3) h: Int = 1 t: Seq[Int] = List(2, 3)

Entonces tu código funciona exactamente como se esperaba.

Esto funciona porque h +: t es equivalente a +:(h,t) cuando se usa para la coincidencia de patten.


Hay dos :: (contras pronunciados) en Scala. Uno es un operador definido en class List y uno es una class (subclase de List ), que representa una lista no vacía caracterizada por una cabecera y una cola.

head :: tail es un patrón constructor, que se modifica sintácticamente desde ::(head, tail) .

:: es una clase de caso, lo que significa que hay un objeto extractor definido para él.


No creo que haya compatibilidad de coincidencia de patrones para secuencias arbitrarias en la biblioteca estándar. Sin embargo, puedes hacerlo sin la coincidencia de patrones:

def doMatch(seq: Seq[Int]) { if (seq.size == 1) println("final element " + seq(0)) else { println("recursing") doMatch(seq.tail) } } doMatch(1 to 10)

Sin embargo, puedes definir tus propios objetos extractores. Ver http://www.scala-lang.org/node/112

object SEQ { def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = { if (s.size == 0) None else { Some((s.head, s.tail)) } } } def doMatch(seq: Seq[Int]) { seq match { case SEQ(head, Seq()) => println("final") case SEQ(head, tail) => { println("recursing") doMatch(tail) } } }


Tipo de trampa, pero aquí va:

def doMatch(seq: Seq[Int]): Unit = seq match { case Seq(x) => println("Final element " + x) case Seq(x, xs@_*) => println("Recursing..." + x); doMatch(xs) }

No me preguntes por qué xs* no funciona ...


Una simple transformación de Seq a List haría el trabajo:

def doMatch (list: List[Int]): Unit = list match { case last :: Nil => println ("Final element.") case head :: tail => println ("Recursing..."); doMatch (tail) case Nil => println ("only seen for empty lists") } def doMatchSeq (seq: Seq[Int]) : Unit = doMatch (seq.toList) doMatch (List(3, 4, 5)) doMatchSeq (3 to 5)