2011-07-27 6 views
8

¿Cuál es la mejor expresión de Scala para hacer coincidir un valor con el n-ésimo elemento de una lista?Coincide con el n-ésimo elemento de una lista en Scala

El enfoque ingenuo, obviamente, no funciona:

scala> val list = List(5,6,7) 
list: List[Int] = List(5, 6, 7) 

scala> val x = 7 
x: Int = 7 

scala> x match { case list(2) => true; case _ => false } 
<console>:10: error: value list is not a case class constructor, nor does it have an  unapply/unapplySeq method 
    x match { case list(2) => true; case _ => false } 

Para clarify- esta pregunta no es acerca de cómo comparar un valor al elemento enésimo de una lista - que es específicamente acerca de si ella puede hacerse usando el emparejamiento.

+4

Si necesita indexar en su secuencia, sería mejor usar 'Vector' en lugar de' List'. – missingfaktor

+1

Cierto, pero si casi todos mis accesos son primordiales, y muy raramente necesito mirar un poco más adentro, entonces 'List' puede ser aún más eficiente en general. –

Respuesta

17

He aquí, el poder del ejemplo extractores! (La clase Regex en el stdlib funciona de manera similar)

case class Nth[A](which: Int) { 
    def unapply(in: List[A]): Option[A] = if (in.size >= which+1) Some(in(which)) else None 
} 

val second = Nth[Int](1) 

List(2,4,6) match { 
    case second(4) => println("yep!") 
    case x => println("nope!") 
} 
+2

Este es un excelente ejemplo de extractor, IMO, aunque probablemente demasiado detallado para una sola vez. Si hubiera una forma de hacerlo sin escribir un extractor personalizado. –

+0

Tenga en cuenta que 'in.size' es O (n); usar 'Seq # lengthCompare' sería más rápido en muchos casos y nunca más lento. –

1

No directamente. Sin embargo, uno de estos puede hacer:

x match { case _ if x == list(2) => true; case _ => false } 

o

val listElem = list(2) 
x match { case `listElem` => true; case _ => false } 
+0

El primer ejemplo es simplemente comparar con el n-ésimo elemento de una lista dentro de un guardia, lo cual es una especie de trampa. El segundo es más como lo que estoy buscando. Lo único feo de eso es que tengo que hacer referencia al n-ésimo elemento antes del partido. –

3

que puede coincidir con la lista:

def l(X : Int) = list match { 
    case _ :: _ :: X :: _ => true 
    case _ => false 
} 

scala> l(4) 
res13: Boolean = false 

scala> l(7) 
res14: Boolean = true 
2

Bueno, List no define un extractor tales, pero se puede :

scala> class IndexOf[T](seq: Seq[T]) { 
    | def unapply(x: T) = seq find (x ==) map (seq indexOf _) 
    | } 
defined class IndexOf 

scala> val list = List(5,6,7) 
list: List[Int] = List(5, 6, 7) 

scala> val listndx = new IndexOf(list) 
listndx: IndexOf[Int] = [email protected] 

scala> val x = 7 
x: Int = 7 

scala> x match { case listndx(2) => true; case _ => false } 
res2: Boolean = true 

N De lo contrario, siempre devolverá la primera coincidencia. La coincidencia de patrones Scala no funciona como Prolog: no alimenta 2 y ve si eso puede ser cierto de alguna manera.

Cuestiones relacionadas