I'm learning Scala and in the below code using flatMap (taken from 99 Scala problems) I have
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
Now Im totally confused what the 'ms' and 'e' are? they must be something key as if I change ms to say dd, I get the error "not found value ms". If I hover over them i get a tool-tip saying 'ms' is a 'List[ ][ ]' and 'e' is 'Any'.
I've tried googling for "Scala List elements ms and e" or "Scala flatMap ms and e" or "Scala what do case ms and case e mean?" but I have not seem to find anything that explains what these 'ms' and 'e' are.
Are they keywords? Where can I find info on them in the Scala documentation?
P.S. I understand the code, but just not what ms and e are
If you're new, let me explain step by step whats going on here.
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
Written verbosely:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap { something =>
something match {
case ms: List[_] => flatten(ms)
case e => List(e)
}
}
What is ms and e?
First let me break this down.
You are flatMapping over a List[Any].
val x = List("Str1", "Str2", "Str3")
val y = x flatMap { elementInList => List(elementInList) }
This means for each element in the list, you are creating a new List with that element in it. Because its a flatMap you essentially get the same (same elements) list back.
Checkout what would happen if you use map instead of flatMap:
val x = List("Str1", "Str2", "Str3")
val y = x map { elementInList => List(elementInList) }
the val y would be:
List(List("Str1"), List("Str2"), List("Str3"))
check out http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/
now, looking at the verbose example:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap { something =>
something match {
case ms: List[_] => flatten(ms)
case e => List(e)
}
}
you are matching on the element in the list or in this case called something.
you are also matching on the elements type.
for example
def myMatch(e: Any): String = {
e match {
case x: String => "Its a String: " + x
case y: Int => "Its a Int: " + y
//notice how im using x twice.. its because they're in separate scope!
case x: Boolean => "Its a Boolean: " + x
case _ => "Its something else!"
}
}
invoke myMatch with the param "hello" and it will return "Its a String: hello".
invoke myMatch with the param 1 and it will return "Its a Int: 1".
check out http://docs.scala-lang.org/tutorials/tour/pattern-matching.html
What is e and ms?
lets look at your code:
def myflatten(somelist : List[Any]): List[Any] = somelist flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
If the element in the list which we are currently looking at is of the type List[_] (the same as List[Any]), we then execute this block, flatten(ms).
ms is the val assigned to the element once matched.
If the element in the list which we are currently looking at is of the type _ or essentially default (case _ =>) then return a List(e) containing one element, which is the element which we were looking at.
This would always return a List[List[Any]]. Which is then flattened to a List[Any].
I hope this helps,
Rhys
Here case ms: List[_] is a typed matching for List type elements. ms is not a keyword, it's just a variable representing element of type List.
And case e is a variable matching, it is kind of catch all scenario. It matches for all elements which are not List (as Lists will be matched by the first case). Again e is also not a keyword.
For more info you can read Kinds of patterns
ms, e - it's only variable names. You can call them as you wish.
In first case:
case ms: List[_] => flatten(ms)
you suppose that content of your list
def myflatten(somelist : List[Any])
can be matched as List[_] of any type
In second case statement:
case e => List(e)
you suppose that content of your list can be anything else.
Read official doc: http://docs.scala-lang.org/tutorials/tour/pattern-matching.html
And here some tutorial: https://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/
to get some background about scala pattern matching.
In general you are comparing with two different cases (ie) case ms having list of any and the other one is of case default specified by e. so if you have list[_] then will implement flat map or else the second option you specified
Related
The flatten function is a function which take a list of list and return a list which is the concatenation of all the lists. As an exercise for functional programming in scala, we have to implement that function with a linear complexity. My solution is :
def flatten[A](l: List[List[A]]): List[A] = {
def outer(ll: List[List[A]]):List[A] = {
ll match {
case Nil => Nil
case Cons(h,t) => inner(t, h)
}
}
def inner(atEnd: List[List[A]], ll: List[A]): List[A] = {
ll match {
case Nil => outer(atEnd)
case Cons(h,t) => Cons(h, inner(atEnd, t))
}
}
outer(l)
}
It works. Now I looked at the solution proposed :
def append[A](a1: List[A], a2: List[A]): List[A] =
a1 match {
case Nil => a2
case Cons(h,t) => Cons(h, append(t, a2))
}
def flatten2[A](l: List[List[A]]): List[A] =
foldRight(l, Nil:List[A])(append)
I am suspicious that flatten2 is really linear. At each iteration of foldLeft, the function append is called. This function will parse all the nodes of the accumulator. The first time, the accumulator is Nil, the second it is l.get(1) then l.get(1) + l.get(2)... So the first list in l won't be crossed only once, but l.length - 1 until the end of the function. Am I right ?
While my implementation really cross each list only once. Is my implementation really faster ?
Consider for example flatten2 (List(List(1,2,3), List(4,5), List(6))), which expands to:
append(List(1,2,3),
append(List(4,5),
append(List(6),
Nil)))
As a comment in the link says, "append takes time proportional to its first argument" and therefore "this function is linear in the total length of all lists". (On the other hand, neither flatten2 nor flatten is tail-recursive, though.)
Suppose I have a the following class:
case class Car(name: String)
then I make a List with instances of Car
val bmw = Car("BMW")
val audi = Car("Audi")
val cars: List[Car] = List(bmw, audi)
I want to have a method which with pattern matching proves if the received list is not a list of type Car / List[Car]
def matchNotCarList[T](list: List[T]) = list match {
case (don´t know) => "It is not a list with Car elements"
case Nil => "empty list"
case _ => "is a list with car elements"
}
How should the first case be??
Notice: I don´t want the case to prove if it is a List[Car], I want it to prove if it is not.
I don´t know if insted of having a List[T] as type parameter I should use List[Any]
Thanks
You could extract the head and check its type:
case h :: _ if !h.isInstanceOf[Car] => "It is not a list with Car elements"
I have questions regarding pattern matching of list prefixes (i.e. the first couple of elements of a list).
This compiles, but it does not work as expected:
val l = List(1,2,3)
val test = { m: List[Int] =>
m match {
case l :: tail => println("tail: "+tail.mkString(","))
case _ => println("no match")
}
}
test(List(1,2,3,4,5))
Output is tail: 2,3,4,5. I'd expect it to say either tail: 4,5, or to fail to match, or to fail at compile time. What makes this work as it does?
My second question is: How can I match a list prefix using a list? I know that this works as I expect:
case 1 :: 2 :: 3 :: tail => println("tail: "+tail.mkString(","))
I have, however, my prefixes as lists, and cannot hard-code them. Is pattern matching even the right thing here?
I know I could do something like
if (m startsWith l) {
val tail = m drop l.size
}
But a long list of these seems rather inelegant, especially in Scala.
Regarding the output of your first code snippet, the l inside of the match is actually a new value that shadows the outer scoped l and captures 1 during execution.
The problem you are encountering is that :: is the unapply for List to break it into exactly a single head value and the tail, deconstructing the linked list.
While there is a ::: operation to go along with ::: to concatenate two lists, it does not have a corresponding unapply which would let you use it in a pattern match in the way you desire.
I don't think this is possible. Closest syntax i could propose based on this workaround:
import collection.SeqLike
implicit class PrefixMatcher[T](prefix: Seq[T]) {
object then {
def unapply[S <: SeqLike[T,S]](seq: S): Option[S] =
if (seq startsWith prefix) Some(seq drop prefix.length) else None
}
}
Then you could use it as
val test: List[Int] => Unit = {
case l.then(tail) => println("tail: " + tail.mkString(","))
case _ => println("no match")
}
Addresing the first part of your question: As #Arne mentions, case l is not being matched against your list, but captures a new list. For the former you'd need to enclose it on backticks, but even then I don't see how you can achieve what you want, the closes I can think of is:
case `l` :+ x => println(s"tail is $s") //but this just works when the tail is just one element long.
For the final part of your question, maybe pattern matching is not the right thing to do here, how about:
val prefixes = List (List (1,2,3), List(4,5,6)...)
def findTail(li:List[Int]) = prefixes.collectFirst{ case p if li.startsWith(p) => li.drop(p.size) } //Option[List[Int]]
This will find the tail for the first prefix that matches the testList or None if there was no match.You can easily generalize it to work with more than just Ints.
I am trying to convert an array of strings into an array of maps(string,string) by mapping each element into the array to (element,regex it matches). My code is as follows, however it throws me error when I run it.
var articles:Array[Map[String,String]] = rawArticles map(x => x, x match {
case ArticleRE(id) => id
case _ => " "
}
)).toMap
rawArticles is the original array and ArticleRE is the regex I am matching.
It appears to me that your issue is trying to call toMap on something that isn't a Seq[(A, B)]. Assuming a trivial case like this (it compiles just fine in Scala 2.10 with a few changes):
val rawArticles = Array("articleOne", "articleTwo", "articleThree")
val articleRE = "(.*)".r
/* some place holder value for no match */
val noMatch = ""
val articles = rawArticles map { x => Map(
x -> x match {
case articleRE(id) => (id, articleRE.toString)
case _ => ("", noMatch)
})
}
I think your issue here was trying to convert a Seq that wasn't a Seq of Tuples, you can also directly use case in Map, as Map can take a PartialFunction.
If you are sure about the types that you want then this should work:
var articles = rawArticles.map(x => Map(x -> (x match {
case ArticleRE(id) => id
case _ => " "
})))
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.
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))
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.
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.