How can I capture multiple variables using pattern matching? - scala

For example:
List(1,2,3,4) match {
case List(x: Int, y: Int, *rest) =>
println(rest) // i want to get List(3,4)
}
_* can match multiple variables but do to seem to be able to capture them.
Thanks!

You can use rest # _* for this:
List(1,2,3,4) match {
case List(x: Int, y: Int, rest # _*) =>
println(rest)
}
Note that this is general: you can use x # pattern to give the name x to any value matched by pattern (provided this value has a suitable type). See http://scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#pattern-binders.

List(1, 2, 3, 4) match {
case _ :: _ :: tail => println(tail) // prints List(3, 4)
}

You can simply match lists by cons operator:
List(1, 2, 3, 4) match {
case x :: y :: rest => println(rest)
} // gives you "List(3, 4)" to stdout

Another way to invoke pattern matching on lists,
val List(x,y,rest # _*) = List(1,2,3,4)
which extracts
x: Int = 1
y: Int = 2
rest: Seq[Int] = List(3, 4)

Related

How to swap to elements in Seq

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)

Pattern matching an int against a set of sets of ints

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

Split a collection to those items that satisfy a predicate, and those that don't [duplicate]

How do I split a sequence into two lists by a predicate?
Alternative: I can use filter and filterNot, or write my own method, but isn't there a better more general (built-in) method ?
By using partition method:
scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))
Good that partition was the thing you wanted -- there's another method that also uses a predicate to split a list in two: span.
The first one, partition will put all "true" elements in one list, and the others in the second list.
span will put all elements in one list until an element is "false" (in terms of the predicate). From that point forward, it will put the elements in the second list.
scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))
You might want to take a look at scalex.org - it allows you to search the scala standard library for functions by their signature. For example, type the following:
List[A] => (A => Boolean) => (List[A], List[A])
You would see partition.
You can also use foldLeft if you need something a little extra. I just wrote some code like this when partition didn't cut it:
val list:List[Person] = /* get your list */
val (students,teachers) =
list.foldLeft(List.empty[Student],List.empty[Teacher]) {
case ((acc1, acc2), p) => p match {
case s:Student => (s :: acc1, acc2)
case t:Teacher => (acc1, t :: acc2)
}
}
I know I might be late for the party and there are more specific answers, but you could make good use of groupBy
val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)
ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))
ret(true)
res3: List[Int] = List(2, 4)
ret(false)
res4: List[Int] = List(1, 3)
This makes your code a bit more future-proof if you need to change the condition into something non boolean.
If you want to split a list into more than 2 pieces, and ignore the bounds, you could use something like this (modify if you need to search for ints)
def split(list_in: List[String], search: String): List[List[String]] = {
def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
val (h1, h2) = list_in2.span({x: String => x!= search})
val new_accum = accum :+ h1
if (h2.contains(search)) {
return split_helper(new_accum, h2.drop(1), search)
}
else {
return accum
}
}
return split_helper(List(), list_in, search)
}
// TEST
// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})

How to split a sequence into two pieces by predicate?

How do I split a sequence into two lists by a predicate?
Alternative: I can use filter and filterNot, or write my own method, but isn't there a better more general (built-in) method ?
By using partition method:
scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))
Good that partition was the thing you wanted -- there's another method that also uses a predicate to split a list in two: span.
The first one, partition will put all "true" elements in one list, and the others in the second list.
span will put all elements in one list until an element is "false" (in terms of the predicate). From that point forward, it will put the elements in the second list.
scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))
You might want to take a look at scalex.org - it allows you to search the scala standard library for functions by their signature. For example, type the following:
List[A] => (A => Boolean) => (List[A], List[A])
You would see partition.
You can also use foldLeft if you need something a little extra. I just wrote some code like this when partition didn't cut it:
val list:List[Person] = /* get your list */
val (students,teachers) =
list.foldLeft(List.empty[Student],List.empty[Teacher]) {
case ((acc1, acc2), p) => p match {
case s:Student => (s :: acc1, acc2)
case t:Teacher => (acc1, t :: acc2)
}
}
I know I might be late for the party and there are more specific answers, but you could make good use of groupBy
val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)
ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))
ret(true)
res3: List[Int] = List(2, 4)
ret(false)
res4: List[Int] = List(1, 3)
This makes your code a bit more future-proof if you need to change the condition into something non boolean.
If you want to split a list into more than 2 pieces, and ignore the bounds, you could use something like this (modify if you need to search for ints)
def split(list_in: List[String], search: String): List[List[String]] = {
def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
val (h1, h2) = list_in2.span({x: String => x!= search})
val new_accum = accum :+ h1
if (h2.contains(search)) {
return split_helper(new_accum, h2.drop(1), search)
}
else {
return accum
}
}
return split_helper(List(), list_in, search)
}
// TEST
// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})

Scala pattern matching on sequences other than Lists

I have the following code which recursively operates on each element within a List
def doMatch(list: List[Int]): Unit = list match {
case last :: Nil => println("Final element.")
case head :: tail => println("Recursing..."); doMatch(tail)
}
Now, ignoring that this functionality is available through filter() and foreach(), this works just fine. However, if I try to change it to accept any Seq[Int], I run into problems:
Seq doesn't have ::, but it does have +:, which as I understand is basically the same thing. If I try to match on head +: tail however, the compiler complains 'error: not found: value +:'
Nil is specific to List, and I'm not sure what to replace it with. I'm going to try Seq() if I ever get past the previous problem
Here is how I think the code should look, except it doesn't work:
def doMatch(seq: Seq[Int]): Unit = seq match {
case last +: Seq() => println("Final element.")
case head +: tail => println("Recursing..."); doMatch(tail)
}
Edit: So many good answers! I'm accepting agilesteel's answer as his was the first that noted that :: isn't an operator in my example, but a case class and hence the difference.
As of the ides of March 2012, this works in 2.10+:
def doMatch(seq: Seq[Int]): Unit = seq match {
case last +: Seq() => println("Final element.")
case head +: tail => println("Recursing..."); doMatch(tail)
} //> doMatch: (seq: Seq[Int])Unit
doMatch(List(1, 2)) //> Recursing...
//| Final element.
More generally, two different head/tail and init/last decomposition objects mirroring append/prepend were added for Seq in SeqExtractors:
List(1, 2) match { case init :+ last => last } //> res0: Int = 2
List(1, 2) match { case head +: tail => tail } //> res1: List[Int] = List(2)
Vector(1, 2) match { case init :+ last => last } //> res2: Int = 2
Vector(1, 2) match { case head +: tail => tail } //> res3: scala.collection.immutable.Vector[Int] = Vector(2)
Kind of cheating, but here it goes:
def doMatch(seq: Seq[Int]): Unit = seq match {
case Seq(x) => println("Final element " + x)
case Seq(x, xs#_*) => println("Recursing..." + x); doMatch(xs)
}
Don't ask me why xs* doesn't work...
There are two :: (pronounced cons) in Scala. One is an operator defined in class List and one is a class (subclass of List), which represents a non empty list characterized by a head and a tail.
head :: tail is a constructor pattern, which is syntactically modified from ::(head, tail).
:: is a case class, which means there is an extractor object defined for it.
You can actually define an object for +: to do exactly what you are looking for:
object +: {
def unapply[T](s: Seq[T]) =
if(s.nonEmpty)
Some(s.head, s.tail)
else
None
}
scala> val h +: t = Seq(1,2,3)
h: Int = 1
t: Seq[Int] = List(2, 3)
Then your code works exactly as expected.
This works because h +: t is equivalent to +:(h,t) when used for patten matching.
I don't think there is pattern matching support for arbitrary sequences in the standard library. You could do it with out pattern matching though:
def doMatch(seq: Seq[Int]) {
if (seq.size == 1) println("final element " + seq(0)) else {
println("recursing")
doMatch(seq.tail)
}
}
doMatch(1 to 10)
You can define your own extractor objects though. See http://www.scala-lang.org/node/112
object SEQ {
def unapply[A](s:Seq[A]):Option[(A, Seq[A])] = {
if (s.size == 0) None else {
Some((s.head, s.tail))
}
}
}
def doMatch(seq: Seq[Int]) {
seq match {
case SEQ(head, Seq()) => println("final")
case SEQ(head, tail) => {
println("recursing")
doMatch(tail)
}
}
}
A simple tranformation from Seq to List would do the job:
def doMatch (list: List[Int]): Unit = list match {
case last :: Nil => println ("Final element.")
case head :: tail => println ("Recursing..."); doMatch (tail)
case Nil => println ("only seen for empty lists")
}
def doMatchSeq (seq: Seq[Int]) : Unit = doMatch (seq.toList)
doMatch (List(3, 4, 5))
doMatchSeq (3 to 5)