Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching on a list in Scala

I'm a little confused regarding pattern matching on a list in Scala.

For example.

    val simplelist: List[Char] = List('a', 'b', 'c', 'd')

    //> simplelist  : List[Char] = List(a, b, c, d)

    def simple_fun(list: List[Char]) = list match {
           case (x:Char) :: (y:List[Char]) => println(x)
           case _ => Nil
     }                                                 
   //> simple_fun: (list: List[Char])Any

   simple_fun(simplelist)                            

   //> a
   //| res0: Any = ()

This currently prints only one line of output. Should it not run/pattern match on each element of the List ?

EDIT: I fixed the compile errors and copied the output from the REPL.

like image 363
Soumya Simanta Avatar asked Oct 24 '12 21:10

Soumya Simanta


3 Answers

Unless you are repeatedly calling simple_fun in some way, what you have there will pattern match the first element and nothing more. To get it to match the whole list, you can get simple_fun to call itself recursively, like this:

val simplelist: List[Char] = List('a', 'b', 'c', 'd')

def simple_fun(list: List[Char]): List[Nothing] = list match {
  case x :: xs => {
    println(x)
    simple_fun(xs)
  }
  case _ => Nil 
}

Note I've also left out some of the types as the Scala compiler can infer them, leaving you with less cluttered, more readable code.

As a small side-note, calling println repeatedly inside the function like that is not particularly functional - as it is all about side effects. A more idiomatic approach would be to have the function construct a string describing the list, which is then output with a single call to println - so the side-effects are kept in a single well-defined place. Something like this would be one approach:

def simple_fun(list: List[Char]):String = list match {
  case x :: xs => x.toString + simple_fun(xs)
  case Nil => ""
}

println(simple_fun(simple_list))
like image 132
Russell Avatar answered Sep 28 '22 00:09

Russell


I would also like to mention that the case for lists can be divided not only the head and tail, as well as any N number of list elements:

def anyFunction(list: List[Int]): Unit =
  list match {
        // ...methods that have already been shown
      case first :: second :: Nil  => println(s"List has only 2 elements: $first and $second")
      case first :: second :: tail => println(s"First: $first \nSecond: $second \nTail: $tail")
  }

Hope it will be useful to someone.

like image 42
S.Dayneko Avatar answered Sep 28 '22 01:09

S.Dayneko


I think the following should work:

def flatten(l: List[_]): List[Any] = l match {
  case Nil => Nil
  case (head: List[_]) :: tail => flatten(head) ::: flatten(tail)
  case head :: tail => head :: flatten(tail)
}

The first line is a match for Nil, so if we don't find anything return nothing. The second line will identify List of Lists and recall the flatten method and flatten the list of lists.

like image 45
Manoj Shah Avatar answered Sep 28 '22 02:09

Manoj Shah