75

My method definition looks as follows

def processLine(tokens: Array[String]) = tokens match { // ...

Suppose I wish to know whether the second string is blank

case "" == tokens(1) => println("empty")

Does not compile. How do I go about doing this?

Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
deltanovember
  • 42,611
  • 64
  • 162
  • 244
  • I don't really understand waht you are trying to achieve. Test whether the second entry of the Array is the empty String and if so, print "empty"? Secondly your "method signature" lacks the return type ascription and includes some code (namely `tokens match {}`). – ziggystar Jul 11 '11 at 08:22

4 Answers4

119

If you want to pattern match on the array to determine whether the second element is the empty string, you can do the following:

def processLine(tokens: Array[String]) = tokens match {
  case Array(_, "", _*) => "second is empty"
  case _ => "default"
}

The _* binds to any number of elements including none. This is similar to the following match on Lists, which is probably better known:

def processLine(tokens: List[String]) = tokens match {
  case _ :: "" :: _ => "second is empty"
  case _ => "default"
}
Ruediger Keller
  • 3,024
  • 2
  • 20
  • 17
  • 3
    how to pattern match the tail? it is left as _* – devssh Aug 08 '18 at 20:28
  • 3
    @devssh `tail @ _*` – Abhijit Sarkar Nov 30 '18 at 14:07
  • So `_*` is an anonymous variable? If I want to print the value of this tail inside the case block what would I do? if I do `case a` then I can use `a` inside the case block, but if I do `case _` that variable will be unusable inside the case block. Can you explain more? I tried using Array(a,b,c) but that will match for array of size 3, not for size n. – devssh Nov 30 '18 at 14:32
12

What is extra cool is that you can use an alias for the stuff matched by _* with something like

val lines: List[String] = List("Alice Bob Carol", "Bob Carol", "Carol Diane Alice")

lines foreach { line =>
  line split "\\s+" match {
    case Array(userName, friends@_*) => { /* Process user and his friends */ }
  }
}
synapse
  • 5,588
  • 6
  • 35
  • 65
7

Pattern matching may not be the right choice for your example. You can simply do:

if( tokens(1) == "" ) {
  println("empty")
}

Pattern matching is more approriate for cases like:

for( t <- tokens ) t match {
   case "" => println( "Empty" )
   case s => println( "Value: " + s )
}

which print something for each token.

Edit: if you want to check if there exist any token which is an empty string, you can also try:

if( tokens.exists( _ == "" ) ) {
  println("Found empty token")
}
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • 3
    That definitely works but seems like the procedural way to do things. I was trying to think in functional terms – deltanovember Jul 11 '11 at 08:14
  • Yes because your question begs procedural answers. For a more functional approach, you can map every element to an Option of string which will be None when the string is empty. You can also wrap the line in a map (or case class) to stop working explicitly whith indices. – paradigmatic Jul 11 '11 at 08:18
  • 6
    @deltanovember The `println` is what makes your code procedural. Your apparent confusion stems from the fact that `if` blocks are expressions, not statements, in Scala (i.e. they return a value and, therefore, are perfectly functional). There's nothing inherently procedural about using an `if` expression rather than pattern matching. – Aaron Novstrup Jul 11 '11 at 19:09
3

case statement doesn't work like that. That should be:

case _ if "" == tokens(1) => println("empty")
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • What happens if I want separate checks for tokens(1), tokens(2), ...? – deltanovember Jul 11 '11 at 08:04
  • +1 for a working solution, but I wonder if the OP was not hoping for some complex array-like expression after the `case` keyword, something like `(_, "", _). Saying `case _` is pretty boring but I think it is all you can do here. Might as well just do away with the match and say `return tokens(1) == ""` :-). – Ray Toal Jul 11 '11 at 08:08
  • 1
    @Ray Toal: see Ruediger Keller's answer. – Alexey Romanov Jul 11 '11 at 08:43
  • 4
    Wow. Scala never ceases to impress. At this rate I'm going to move _completely_ away from ML. – Ray Toal Jul 11 '11 at 08:49