Pattern matching in scala on Seq[Any] - scala

I am not a scala expert but I would like to avoid use of asInstanceOf and replace that with pattern matching for sequences. Following snipped gives me an error non-variable type argument
val seq : Seq[Any] = getSeq();
val rec = seq match {
case rec: Seq[Record[Key, Value]] => rec
case other => throw new Exception(s"Expected a Seq[Record[Key, Value]]")
}
I have following code with asInstanceOf which works, but would like to replace it:
val values = seq.asInstanceOf[Seq[Record[Key, Vrade]]].map(_.value)

You could map the elements to a new list with a type Seq[Record[Key, Vrade]]. So instead of matching the whole sequence, you match on the elements within the list.
It would be something like:
val values = seq.map {
case x: Record[Key, Vrade]] => Some(x);
case _ => None;
};
And then afterwards you can flatten it, or flatmap it to begin with, if you have the variable as List instead og Seq

Related

foreach loop in scala

In scala foreach loop if I have list
val a = List("a","b","c","d")
I can print them without a pattern matching like this
a.foreach(c => println(c))
But, if I have a tuple like this
val v = Vector((1,9), (2,8), (3,7), (4,6), (5,5))
why should I have to use
v.foreach{ case(i,j) => println(i, j) }
a pattern matching case
{ brackets
Please explain what happens when the two foreach loops are executed.
You don't have to, you choose to. The problem is that the current Scala compiler doesn't deconstruct tuples, you can do:
v.foreach(tup => println(tup._1, tup._2))
But, if you want to be able to refer to each element on it's own with a fresh variable name, you have to resort to a partial function with pattern matching which can deconstruct the tuple.
This is what the compiler does when you use case like that:
def main(args: Array[String]): Unit = {
val v: List[(Int, Int)] = scala.collection.immutable.List.apply[(Int, Int)](scala.Tuple2.apply[Int, Int](1, 2), scala.Tuple2.apply[Int, Int](2, 3));
v.foreach[Unit](((x0$1: (Int, Int)) => x0$1 match {
case (_1: Int, _2: Int)(Int, Int)((i # _), (j # _)) => scala.Predef.println(scala.Tuple2.apply[Int, Int](i, j))
}))
}
You see that it pattern matches on unnamed x0$1 and puts _1 and _2 inside i and j, respectively.
According to http://alvinalexander.com/scala/iterating-scala-lists-foreach-for-comprehension:
val names = Vector("Bob", "Fred", "Joe", "Julia", "Kim")
for (name <- names)
println(name)
To answer #2: You can only use case in braces. A more complete answer about braces is located here.
Vector is working a bit differently, you using function literals using case...
In Scala, we using brackets{} which accept case...
{
case pattern1 => "xxx"
case pattern2 => "yyy"
}
So, in this case, we using it with foreach loop...
Print all values using the below pattern then:
val nums = Vector((1,9), (2,8), (3,7), (4,6), (5,5))
nums.foreach {
case(key, value) => println(s"key: $key, value: $value")
}
Also you can check other loops like for loop as well if you think this is not something which you are comfortable with...

Retrieve tuple from string

I have the following input string:
"0.3215,Some(0.5123)"
I would like to retrieve the tuple (0.3215,Some(0.5123)) with: (BigDecimal,Option[BigDecimal]).
Here is one of the thing I tried so far:
"\\d+\\.\\d+,Some\\(\\d+\\.\\d+".r findFirstIn iData match {
case None => Map[BigDecimal, Option[BigDecimal]]()
case Some(s) => {
val oO = s.split(",Some\\(")
BigDecimal.valueOf(oO(0).toDouble) -> Option[BigDecimal](BigDecimal.valueOf(lSTmp2(1).toDouble))
}
}
Using a Map and transforming it into a tuple.
When I try directly the tuple I get an Equals or an Object.
Must miss something here...
Your code has several issues, but the big one seems to be that the case None side of the match returns a Map but the Some(s) side returns a Tuple2. Map and Tuple2 unify to their lowest-common-supertype, Equals, which is what you're seeing.
I think this is what you're trying to achieve?
val Pattern = "(\\d+\\.\\d+),Some\\((\\d+\\.\\d+)\\)".r
val s = "0.3215,Some(0.5123)"
s match {
case Pattern(a,b) => Map(BigDecimal(a) -> Some(BigDecimal(b)))
case _ => Map[BigDecimal, Option[BigDecimal]]()
}
// Map[BigDecimal,Option[BigDecimal]] = Map(0.3215 -> Some(0.5123))

Work around type-erasure when doing pattern-match of a list / sequence in Scala

I'm having a situation like this:
I have a sequence that I need to match. Actually, in the "case" I only need to match against a sequence whose elements are of tuple (String, Seq[String]) but I couldn't find a way to do that, so I resorted to the technique I read on web: decapitate the seq, match against the first element, and re-attach inside the block to get the original seq.
The problem with that approach is: type erasure.
The resulting seq from the expression "head +: rest" is a Seq[Any] instead of Seq[(String, Seq[String])]
That's why the tuple_.1 gives compile error (line 153 in the attached image).
How to work around this situation?
It was my bad, there are a couple of coding errors in the above screenshot; from the case block of sequence matching I should have added another line to the end: complexSeqReconstructed.
Apart from that, there's a little detail: from the "case Nil", I also have to return an empty Seq of type Seq[(String, Seq[String])] ... that matches the return from the other case. That way Scala will correctly perform type inference. Otherwise the line hhh.map wouldn't compile (it will say, Object hhh doesn't have map method).
So here's the updated (working) code:
val theComplexSeq: Seq[(String, Seq[String])] = Seq(
("the_key_a", Seq("value_a_1", "value_a_2"))
)
val hhh = theComplexSeq match {
case Nil => {
Seq[(String, Seq[String])]()
}
case (head: (String, Seq[String])) +: rest => {
println(head)
println(rest)
val complexSeqReconstructed = head +: rest
println(complexSeqReconstructed)
complexSeqReconstructed
}
}
hhh.map {tuple =>
println(tuple._1 + "->" + tuple._2)
tuple
}

Scala Map pattern matching

How to do pattern matching on a Map in Scala ?
A (non working) attempt includes,
Map("a"->1, "b"->2, "c"->3) match {
case Map(a,b,_*) => a
}
which errs with
value Map is not a case class, nor does it have an unapply/unapplySeq member
case Map(a,b,_*) => a
The error is indicative enough, yet how to enrich Map with an unapply method for pattern matching ?
Many Thanks
Update
Following #Paul's comment, a neater use case may be like this,
Map("a"->1, "b"->2, "c"->3) match {
case Map("b"->2,_*) => "222"
}
namely, in this case, if map contains key b that maps onto value 2.
Most easy way is tramsform Map to List:
Map("a"->1, "b"->2, "c"->3).to[List] match {
case List(a,b,_*) => a
}
An approach to enriching Map with an unapplySeq method for pattern matching includes this,
object MapExtractor {
def unapplySeq[A <% Ordered[A], B <% Ordered[B]]
(s: Map[A,B]): Option[Seq[(A,B)]] = Some(s.toSeq.sorted)
}
where the sorting approach may be changed to any orderable (items comparable) logic. In this example,
Map("b"->2, "a"->1, "c"->3) match {
case MapExtractor ( x, xs # _* ) => println(s"x: $x") ; println(s"xs: $xs")
}
delivers
x: (a,1)
xs: ArrayBuffer((b,2), (c,3))

Convert Scala foreach to .map

I'm new to Scala and I'm trying to convert code of the form
val series: ListBuffer[Seq[Seq[Any]]] = ListBuffer[Seq[Seq[Any]]]()
points.foreach(point => {
if( conditionA )
series += doA(...) // returns a ListBuffer[Seq[Any]]
else
series += doB(...) // returns a ListBuffer[Seq[Any]]
})
to use .map(). I'm thinking its something like:
val series: ListBuffer[Seq[Seq[Any]]] = points.map(point => {
case conditionA => doA(...)
case _ => doB(...)
})
but this doesn't compile because (I believe) the mapped sequences get appended as a single Seq[Any] instead of Seq[Seq[Any]], so I get the error
Expression of type Seq[Any] doesn't conform to expected type ListBuffer[Seq[Seq[Any]]]
Any ideas? Is there something wrong with syntax?
Let me suppose a few things, you have some function def doA(arg1: A): ListBuffer[Seq[Any]] such that you ultimately want to arrive at a List[Seq[Any]] as the final result type after mapping this function over your collection. Then what you want is flatMap instead of map:
val series = points flatMap{
case point if conditionA(point) => doA(point) result ()
case point => doB(point) result ()
}
The reason I make such a supposition is that the only reason you'd ever want to use a ListBuffer[A] in the general form is to create a List[A] through some side-effecting expression. Hence, you ultimately want a List[Seq[A]] as your final output.