Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match to the n-th element of a list in Scala

Tags:

scala

What is the best Scala idiom for matching a value to the n-th element of a list?

The naive approach obviously doesn't work:

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 }

To clarify- this question is not about how to compare a value to the n-th element of a list - it is specifically about whether it can be done using matching.

like image 318
enhanced_null Avatar asked Jul 27 '11 06:07

enhanced_null


4 Answers

Behold, the power of instance extractors! (the Regex class in the stdlib works similarly)

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!")
}
like image 198
Alex Cruise Avatar answered Oct 22 '22 08:10

Alex Cruise


you can match the list:

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

scala> l(4)
res13: Boolean = false

scala> l(7)
res14: Boolean = true
like image 26
onof Avatar answered Oct 22 '22 07:10

onof


Well, List doesn't define such an extractor, but you can:

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] = IndexOf@35cd1217

scala> val x = 7
x: Int = 7

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

Note that this will always return the first match. Scala pattern matching does not work like Prolog -- it doesn't feed 2 and see if that can be true somehow.

like image 28
Daniel C. Sobral Avatar answered Oct 22 '22 09:10

Daniel C. Sobral


Not directly. However, one of these may do:

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

or

val listElem = list(2)
x match { case `listElem` => true; case _ => false }
like image 41
Alexey Romanov Avatar answered Oct 22 '22 09:10

Alexey Romanov