Example:
you have two lists ("categories"):
catLow = [1,2,3,4,5]
catHigh = [6,7,8,9,10]
Using pattern matching, how do you decide whether
val x = 7
Is within the first list (category) or the second one?
That's the general problem. My specific problem is doing that but in my case X is within a list as in:
val l = [1,7,2,4]
and I want to match it against something like:
case catHigh :: tail // i.e. starts with a "high" number
case _ :: catLow :: tail // i.e. second element is a "low" number
// where "high" and "low" are example category names implemented as lists
val lowSet = Set(1, 2, 3, 4, 5)
val highSet = Set(6, 7, 8, 9, 10)
someList match {
case catHigh :: tail if highSet(catHigh) => ...
case _ :: catLow :: tail if lowSet(catLow) => ...
}
A Set can be used as a function that returns whether the passed element is in the Set. Then, in the match statement, you can use pattern guards (introduced with if) to check whether matched values are in the set.
You could do something like this:
scala> class Cat( xs:Set[Int] ) {
def unapply( x:Int ) = if ( xs contains x ) Some(x) else None
}
defined class Cat
scala> object CatLow extends Cat( Set(1,2,3,4,5) )
defined object CatLow
scala> object CatHigh extends Cat( Set(6,7,8,9,10) )
defined object CatHigh
scala> def decode( zs:List[Int] ):Unit = zs match {
case Nil =>
case CatLow(z)::tail =>
println("Low "+z)
decode(tail)
case CatHigh(z)::tail =>
println("High "+z)
decode(tail)
case z::tail =>
println("???? "+z)
decode(tail)
}
decode: (zs: List[Int])Unit
scala> decode( List(1,7,2,0,4) )
Low 1
High 7
Low 2
???? 0
Low 4
Related
I have an exercise where I have to swap elements on even and odd positions.
For example, from Seq(1,2,3,4,5) I have to get Seq(2,1,4,3,5).
I wanted to use sliding and then swap two elements in the slid Seq, but sliding will take something like this: (1,2) (2,3) (3,4) (4,5), won't it? Is there any function to take only unique pairs?
Start with grouped().
mySeq.grouped(2).flatMap{
case Seq(a,b) => Seq(b,a)
case x => x
}.toList
Alternatively, another good generic approach is pattern matching:
val testList: List[Int] = List(1, 2, 3, 4, 5)
def swapEvenAndOddElementsRecursively( listToSwap: List[Int]): List[Int] = {
listToSwap match {
// Base Cases (2) Empty list and list with single element
case Nil | _ :: Nil => listToSwap
// Recursive case take 2 elements swap and process rest of list
case firstElement :: secondElement :: rest => secondElement :: firstElement :: swapEvenAndOddElementsRecursively(rest)
}
}
#tailrec
final def swapEvenAndOddElementsWithTailRecursion( listToSwap: List[Int], result: List[Int] = List.empty): List[Int] = {
listToSwap match {
// Base Case (1) Empty list
case Nil => result
// Base Case (2) List with single element
case singleNumber :: Nil => result ::: List(singleNumber)
// Recursive case take 2 elements swap, append to result, and process rest of list
case firstElement :: secondElement :: rest =>
val updatedResult: List[Int] = result ::: List(secondElement, firstElement)
// val updatedResult: List[Int] = (firstElement :: secondElement :: result.reverse).reverse
swapEvenAndOddElementsWithTailRecursion(rest, updatedResult)
}
}
println(swapEvenAndOddElementsRecursively(testList))
// List(2, 1, 4, 3, 5)
println(swapEvenAndOddElementsWithTailRecursion(testList))
// List(2, 1, 4, 3, 5)
Note that for the tail recursive optimization, the method must be declared as either final or private (it cannot be overridden) and it must have linear pattern (one recursive case, arbitrary number of base cases)
What is the correct syntax for something like the following?
var foo = 0
someIterator.foreach{ x => x.property match {
case "a" => foo += 1
case "b" => yield "current foo" + foo
}}
I.e., I'm trying to iterate over someIterator. When it matches one thing, it should update a local variable via closure; when it encounters another, it should yield some derivation of the current state to the resulting iterator preserving the state for successive iterations.
You can use Option[String], unlift and collect.
unlift takes a function that returns an option and turns it into a partial function.
collect is like map, except it considers only the elements for which the partial function is defined.
The following example demonstrates the approach:
import Function.unlift
var foo = 0
someIterator.map(_.property).collect(unlift {
case "a" => foo += 1; None
case "b" => Some("current foo" + foo)
})
Live Demo
If you just want to have the final value of foo then you can use tail recursion and you won't have to use a mutable variable too.
#annotation.tailrec
def f(l: List[Char], foo: Int = 0):Int= {
if (l == Nil) foo
else {
l.head match {
case 'a' => f(l.tail, foo + 1)
case 'b' => f(l.tail, foo)
}
}
}
val l1 = List('a','b')
f(l1)
l1: List[Char] = List(a, b)
res0: Int = 1
You can use scanLeft's acumulator instead of variable:
someIterator.scanLeft((0, None: Option[String])){
case ((foo, _), "a") => (foo + 1, None)
case ((foo, _), "b") => (foo, Some(s"current foo $foo"))
}.map(_._2).flatten
Example:
val someIterator = List("a","a","a","a","b", "a", "a", "b").toIterator
scala> someIterator.scanLeft(...){...}.map(_._2).flatten
res16: Iterator[String] = non-empty iterator
scala> res16.toList
res17: List[String] = List(current foo 4, current foo 6)
So you still have an iterator as a result
Let's say I have this collection:
val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))
Is there a way to define an extractor which would work in the following way:
a.foreach(e => {
e match {
case Array( ending with 5 ) =>
case _ =>
}
})
Sorry for the pseudocode, but I don't know how to express it. Is there a way to match something having 5 as the last element? What if I would want to match something having a 1 as the first element and a 5 as the last? Could this work for arrays of various lengths ( note that I specifically chose different lengths for my arrays in the example ).
Thanks!
Yes you can:
object EndsWith {
def unapply[A]( xs: Array[A] ) =
if( xs.nonEmpty ) Some( xs.last ) else None
}
On your example:
val a = Array(Array(1,2,3,4,5),Array(4,5),Array(5),Array(1,2,6,7,8))
a foreach {
case e # EndsWith(5) => println( e.mkString("(",",",")" ) )
case _ =>
}
It prints as expected (1,2,3,4,5), (4,5) and (5)
With the same approach, you could write an extractor StartWith and then add a method to combine them in a new extractor matching both conditions.
a.foreach(e => {
e match {
case a: Array[Int] if a.last == 5 =>
case _ =>
}
})
You can do something a little better for matching on the first elements:
a.foreach(e => {
e match {
case Array(1, _*) =>
case _ =>
}
})
Unfortunately the #_* thing has to be the last item in the list of array arguments. But you can make the matching before that as complex as you want.
scala> val Array(1, x #_*) = Array(1,2,3,4,5)
x: Seq[Int] = Vector(2, 3, 4, 5)
scala> val Array(1, b, 3, x #_*) = Array(1,2,3,4,5)
b: Int = 2
x: Seq[Int] = Vector(4, 5)
The case syntax supports ifs, so this would work:
a foreach {
case a: Array[Int] if a.last == 5 =>
case _ =>
}
a.foreach (ar => ar.last match {
case 5 => println ("-> 5] " + ar.mkString ("~"))
case _ => println (" ?] " + ar.mkString (":")) })
Why don't you match directly for the last element?
-> 5] 1~2~3~4~5
-> 5] 4~5
-> 5] 5
?] 1:2:6:7:8
I am trying to understand the Scala quicksort example from Wikipedia. How could the sample be disassembled step by step and what does all the syntactic sugar involved mean?
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
As much as I can gather at this stage qsort is a function that takes no parameters and returns a new Function1[List[Int],List[Int]] that implements quicksort through usage of pattern matching, list manipulation and recursive calls. But I can't quite figure out where the pivot comes from, and how exactly the pattern matching syntax works in this case.
UPDATE:
Thanks everyone for the great explanations!
I just wanted to share another example of quicksort implementation which I have discovered in the Scala by Example by Martin Odersky. Although based around arrays instead of lists and less of a show-off in terms of varios Scala features I personally find it much less convoluted than its Wikipedia counterpart, and just so much more clear and to the point expression of the underlying algorithm:
def sort(xs: Array[Int]): Array[Int] = {
if (xs.length <= 1) xs
else {
val pivot = xs(xs.length / 2)
Array.concat(
sort(xs filter (pivot >)),
xs filter (pivot ==),
sort(xs filter (pivot <)))
}
}
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
let's pick apart a few bits.
Naming
Operators (such as * or +) are valid candidates for method and class names in Scala (hence you can have a class called :: (or a method called :: for that matter - and indeed both exist). Scala appears to have operator-overloading but in fact it does not: it's merely that you can declare a method with the same name.
Pattern Matching
target match {
case p1 =>
case p2 =>
}
Where p1 and p2 are patterns. There are many valid patterns (you can match against Strings, types, particular instances etc). You can also match against something called an extractor. An extractor basically extracts arguments for you in the case of a match, so:
target match {
case MyExtractor(arg1, arg2, arg3) => //I can now use arg1, arg2 etc
}
In scala, if an extractor (of which a case class is an example) exists called X, then the pattern X(a, b) is equivalent to a X b. The case class :: has a constructor taking 2 arguments and putting this together we get that:
case x :: xs =>
case ::(x, xs) =>
Are equivalent. This match says "if my List is an instance of :: extract the value head into x and tail into xs". pattern-matching is also used in variable declaration. For example, if p is a pattern, this is valid:
val p = expression
This why we can declare variables like:
val x :: xs = List(1, 2, 3)
val (a, b) = xs.partition(_ % 2 == 0 ) //returns a Tuple2 which is a pattern (t1, t2)
Anonymous Functions
Secondly we have a function "literal". tail is an instance of List which has a method called partition which takes a predicate and returns two lists; one of those entries satisfying the predicate and one of those entries which did not.
val pred = (el: Int) => e < 2
Declares a function predicate which takes an Int and returns true iff the int value is less than 2. There is a shorthand for writing functions inline
tail.partition(_ < pivot) // _ is a placeholder for the parameter
tail.partition( (e: Int) => e < pivot )
These two expressions mean the same thing.
Lists
A List is a sealed abstract class with only two implementations, Nil (the empty list) and :: (also called cons), which is a non-empty list consisting of a head and a tail (which is also a list). You can now see that the pattern match is a match on whether the list is empty or not. a List can be created by cons-ing it to other lists:
val l = 1 :: 2 :: Nil
val m = List(1, 2, 3) ::: List(4, 5, 6)
The above lines are simply method calls (:: is a valid method name in scala). The only difference between these and normal method calls is that, if a method end in a colon : and is called with spaces, the order of target and parameter is reversed:
a :: b === b.::(a)
Function Types
val f: A => B
the previous line types the reference f as a function which takes an A and returns a B, so I could then do:
val a = new A
val b: B = f(a)
Hence you can see that def qsort: List[Int] => List[Int] declares a method called qsort which returns a function taking a List[Int] and returning a List[Int]. So I could obviously do:
val l = List(2, 4, 1)
val m = qsort.apply(l) //apply is to Function what run is to Runnable
val n = qsort(l) //syntactic sugar - you don't have to define apply explicitly!
Recursion
When a method call is tail recursive, Scala will optimize this into the iterator pattern. There was a msitake in my original answer because the qsort above is not tail-recursive (the tail-call is the cons operator)
def qsort: List[Int] => List[Int] = {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
Let's rewrite that. First, replace the function literal with an instance of Function1:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = input match {
case Nil => Nil
case pivot :: tail =>
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
}
}
Next, I'm going to replace the pattern match with equivalent if/else statements. Note that they are equivalent, not the same. The bytecode for pattern matches are more optimized. For instance, the second if and the exception throwing below do not exist, because the compile knows the second match will always happen if the first fails.
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult._1
val tail = unapplyResult._2
val (smaller, rest) = tail.partition(_ < pivot)
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Actually, val (smaller, rest) is pattern match as well, so Let's decompose it as well:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val tmp0 = tail.partition(_ < pivot)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort(smaller) ::: pivot :: qsort(rest)
} else {
throw new scala.MatchError(input)
}
}
Obviously, this is highly unoptmized. Even worse, there are some function calls being done more than once, which doesn't happen in the original. Unfortunately, to fix that would require some structural changes to the code.
There's still some syntactic sugar here. There is an anonymous function being passed to partition, and there is the syntactic sugar for calling functions. Rewriting those yields the following:
def qsort: List[Int] => List[Int] = new Function1[List[Int], List[Int]] {
def apply(input: List[Int]): List[Int] = if (input == Nil) {
Nil
} else if (input.isInstanceOf[::[_]] &&
scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]) != None) {
val unapplyResult0 = scala.collection.immutable.::.unapply(input.asInstanceOf[::[Int]]).get
val pivot = unapplyResult0._1
val tail = unapplyResult0._2
val func0 = new Function1[Int, Boolean] {
def apply(input: Int): Boolean = input < pivot
}
val tmp0 = tail.partition(func0)
if (Tuple2.unapply(tmp0) == None)
throw new scala.MatchError(tmp0)
val unapplyResult1 = Tuple2.unapply(tmp0).get
val smaller = unapplyResult1._1
val rest = unapplyResult1._2
qsort.apply(smaller) ::: pivot :: qsort.apply(rest)
} else {
throw new scala.MatchError(input)
}
}
For once, the extensive explanations about each syntactic sugar and how it works are being done by others. :-) I hope this complements their answers. Just as a final note, the following two lines are equivalent:
qsort(smaller) ::: pivot :: qsort(rest)
qsort(rest).::(pivot).:::(qsort(smaller))
The pivot in this pattern matching example is the first element of the list:
scala> List(1,2,3) match {
| case x :: xs => println(x)
| case _ => println("empty")
| }
1
The pattern matching is based on extractors and the cons is not part of the language. It uses the infix syntax. You can also write
scala> List(1,2,3) match {
| case ::(x,xs) => println(x)
| case _ => println("empty")
| }
1
as well. So there is a type :: that looks like the cons operator. This type defines how it is extracted:
final case class ::[B](private var hd: B, private[scala] var tl: List[B]){ ... }
It's a case class so the extractor will be generated by the Scala compiler. Like in this example class A.
case class A(x : Int, y : Int)
A(1,2) match { case x A y => printf("%s %s", x, y)}
-> 1 2
Based on this machinary patterns matching is supported for Lists, Regexp and XML.
I've an initial list that consists in different types of elements and I've to filter it to just take the int and double values.
For example (1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil) should become (1, 100, 3.14, List(10), (5,7))
I'm having trouble coming up with a solution because once the list is passed to a method it becomes a List[Any] type of list and I need to know the type of each element before casting it. It wouldn't be a problem it didn't contain others substructures such as tuples as I could manage something with a pattern matching.
Is it possible somehow to get the specific type of a Any element and to cast it?
As an academic exercise it's rather silly. You should be learning how to avoid situations like this instead of trying to deal with it. Still, bad code can be rather instructive at times.
def intOrDbl(la :List[Any]) :List[Any] = la.flatMap{
case i:Int => List(i)
case d:Double => List(d)
case l:List[_] => List(intOrDbl(l))
case t:Product => val res = intOrDbl(t.productIterator.toList)
res.length match {
case 0 => Nil
case 1 => List(res)
case 2 => List((res(0),res(1)))
case 3 => List((res(0),res(1),res(2)))
case 4 => List((res(0),res(1),res(2),res(3)))
// etc.
}
case _ => Nil
}
val data = 1 :: "hello" :: 100 :: 3.14 :: ('a'::10::Nil) :: 'c' :: (5,7,'a') :: Nil
intOrDbl(data)
//res0: List[Any] = List(1, 100, 3.14, List(10), (5,7))
One choice you have is to put your result type into an ADT. Here is how it might work:
sealed trait IntOrDoubleOrList
case class IntValue(value: Int) extends IntOrDoubleOrList
case class DoubleValue(value: Double) extends IntOrDoubleOrList
case class ListValue(value: List[IntOrDoubleOrList]) extends IntOrDoubleOrList
def filterIntOrDouble(l: List[_]): List[IntOrDoubleOrList] = {
l.collect({
case iv: Int => IntValue(iv)
case dv: Double => DoubleValue(dv)
case lv: List[_] => ListValue(filterIntOrDouble(lv))
})
}
def test(): Unit = {
val origList = (1 :: "hello" :: 100 :: 3.14 :: ('a' :: 10 :: Nil) :: 'c' :: (5, 7, 'a') :: Nil)
val f = filterIntOrDouble(origList)
println(f)
}
Depending on you further needs you may extend the IntOrDoubleOrList trait with some helper methods like foreach(intHandler: Int => Unit, doubleHandler: Double => Unit)