What is the idiomatic way to pattern match sequence comprehensions?

11,572

Well, you can pattern-match any sequence:

case Seq(a, b, rest @ _ *) =>

For example:

scala> def mtch(s: Seq[Int]) = s match { 
  |      case Seq(a, b, rest @ _ *) => println("Found " + a + " and " + b)
  |      case _ => println("Bah") 
  |    }
mtch: (s: Seq[Int])Unit

Then this will match any sequence with more than (or equal to) 2 elements

scala> mtch(List(1, 2, 3, 4))
Found 1 and 2

scala> mtch(Seq(1, 2, 3))
Found 1 and 2

scala> mtch(Vector(1, 2))
Found 1 and 2

scala> mtch(Vector(1))
Bah
Share:
11,572
letmaik
Author by

letmaik

All original source snippets I post on stackoverflow are dedicated to the public domain. Do with them as you see fit.

Updated on June 05, 2022

Comments

  • letmaik
    letmaik almost 2 years
    val x = for(i <- 1 to 3) yield i
    x match {
        case 1 :: rest => ... // compile error
    }
    

    constructor cannot be instantiated to expected type; found : collection.immutable.::[B] required: scala.collection.immutable.IndexedSeq[Int]

    This is the same problem as MatchError when match receives an IndexedSeq but not a LinearSeq.

    The question is, how to do it right? Adding .toList everywhere doesn't seem right. And creating an own extractor which handles every Seq (as described in the answer of the other question) would lead to a mess if everybody would do it...

    I guess the question is, why can't I influence what the return type of sequence comprehensions is, or: why isn't such a generalized Seq extractor part of the standard library?

  • letmaik
    letmaik almost 12 years
    I get scala.MatchError: Vector(1, 2, 3) (of class scala.collection.immutable.Vector) with that. Isn't it possible to only match case classes like that?
  • oxbow_lakes
    oxbow_lakes almost 12 years
    It's possible to match anything with an extractor - in this case, anything with an unapplySeq method.
  • letmaik
    letmaik almost 12 years
    Somewhere I read that instead of using List in method signatures it's better to use Seq if that also describes the problem. So if I have Seq everywhere, should I then always use Seq(..) pattern matching as the idiomatic way? Because with Seq I probably shouldn't match on List or :: anyway. Or wait for 2.10 and use +: everywhere?
  • oxbow_lakes
    oxbow_lakes almost 12 years
    Well, 2.10 is several months away. I would usually use List myself, unless I am converting some huge data structure, in which case pattern-matching might not be the best bet anyway. If you are just testing for emptiness, you can always use headOption
  • letmaik
    letmaik almost 12 years
    What I actually do now is matching Seq() for empty seqs, Seq(a,b) for fixed numbers of elements and a +: rest for head tail matching. I actually copied the relevant extractors into my project and created package objects with +: and :+ for each package so that I don't have to import anything and can just delete those once 2.10 comes out.