Using for comprehension in Scala - scala

def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = occurrences match {
case Nil => Nil
case x :: xs => for(z <- combinations(xs); y <- occ(x)) yield (y :: z)
}
def occ(e: (Char, Int)): List[(Char, Int)] = (for(i <- 0 to e._2) yield (e._1, i)).toList
Hi,
I can't find any flaw in the above snippet but it still giving me List() for any input.

Well, I think you are pretty close to the answer. The most important thing is to consider what is the right return value in case of Nil.
def combinations(occurrences: Occurrences): List[Occurrences] = occurrences match {
case Nil => List(List())
case x :: xs =>
for {
z <- combinations(xs)
n <- 0 to x._2
} yield (if (n == 0) z else (x._1, n) :: z)
}

You're first for comprehension will always yield a Nil at the end of your recursion which will force the rest of your recursion to be Nil. Here's a slightly modified version that works, though it gives a List[(Char, Int)] instead of a List[List[(Char, Int)]]:
def combinations(occurrences: List[(Char,Int)]): List[(Char,Int)] = occurrences match {
case Nil => Nil
case x :: xs => (for { z <- combinations(xs) } yield z) ::: occ(x)
}
If the first part of your for comprehension returns Nil, then it won't evaluate the rest of it and will just return Nil. I've changed things around a bit, so now even if it does evaluate to Nil, it will be combined with the results of occ.

def combinations(occurrences: List[(Char,Int)]): List[List[(Char,Int)]] = occurrences match {
case Nil => List(List())
case x :: xs => for(z <- combinations(xs); y <- occ(x)) yield (y :: z)
}
def occ(e: (Char, Int)): List[(Char, Int)] = (for(i <- 0 to e._2) yield (e._1, i)).toList
This has solved my problem!!!

Related

How to filter list which elements are in non decreasing order

How can I filter list of other list, e.g.
val l = List(List(1,2,3), List(1,2,4), List(9,8,7))
to return a List of elements that are not in descending order and sum of elements in the list is odd. So it should return List(1,2,4) (sum is 7 and elements are in not descending order).
I was thinking about something like l.filter( _ < _ ).filter( _ + _ % 2 != 0) but I don't really know how to do this.
You can check whether the sorted list is the same as the list itself:
val filtered = l.filter(x => x.sorted == x && x.sum % 2 != 0)
Tail recursive method as #Luis noted:
def isAscendingAndOddSum(xss: List[List[Int]]): List[List[Int]] = {
#scala.annotation.tailrec
def isAscendingAndOddSumR(xss: List[List[Int]], acc: List[List[Int]]): List[List[Int]] = xss match {
case Nil => acc
case h::t if(h.sorted == h && h.sum % 2 != 0) => isAscendingAndOddSumR(t, h :: acc)
case h::t => isAscendingAndOddSumR(t, acc)
}
isAscendingAndOddSumR(xss, List())
}
scala> isAscendingAndOddSum(List(List(1,2,3), List(1,2,4), List(9,8,7)))
val res11: List[List[Int]] = List(List(1, 2, 4))

A "Simple' Scala question but took me long time to debug

Please check the two pieces of script as above.
genComb4(lst) works since I put z <- genComb4(xs) before i <- 0 to x._2 in the for-comprehension; genComb(lst) does not work since I change the order of these two lines in for-comprehension.
It took me almost half day to find this bug, but I cannot explain it by myself. Could you tell me why this happened?
Thank you very much in advance.
// generate combinations
val nums = Vector(1, 2, 3)
val strs = Vector('a', 'b', 'c')
val lst: List[(Char, Int)] = strs.zip(nums).toList
def genComb4(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
z <- genComb4(xs) // correct
i <- 0 to x._2 // correct
} yield ( (x._1, i) :: z)
}
genComb4(lst)
def genComb(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
i <- (0 to x._2) // wrong
z <- genComb(xs) // wrong
} yield ( (x._1, i) :: z)
}
genComb(lst)
It's because of different types of container in for comprehension. When you start for-comprehension from line: i <- (0 to x._2) it's set type of result container as IndexedSeq but in case where first line is z <- genComb4(xs) the type of result container is List, take a look:
val x = 'a' -> 2
val indices: Seq[Int] = 0 to x._2
val combs: List[List[(Char, Int)]] = genComb4(List(x))
// indexed sequence
val indicesInFor: IndexedSeq[(Char, Int)] = for {
i <- 0 to x._2
} yield (x._1, i)
// list
val combsInFor: List[List[(Char, Int)]] = for {
z <- genComb4(List(x))
} yield z
so for make your second case is working, you should cast (0 to x._2).toList:
val indicesListInFor: List[(Char, Int)] = for {
i <- (0 to x._2).toList
} yield (x._1, i)
result code should be:
def genComb(lst: List[(Char, Int)]): List[List[(Char, Int)]] = lst match {
case Nil => List(List())
case x :: xs =>
for {
i <- (0 to x._2).toList
z <- genComb(xs)
} yield ( (x._1, i) :: z)
}
genComb(lst)
You should remember about type of starting line in for-comprehension and inheritance of scala collections. If next types in for-comprehension can't be converted by inheritance rules to the first expression line type you should take care about it by yourself.
Good practise is unwrap for-expression into flatMap, map and withFilter functions, then you will find miss-typing or something else faster.
useful links:
how does yield work, scala documentation
quick review of scala for-comprehensions
for-expressions, scala documentation

Scala Recursion Over Multiple Lists

I have this function that takes two lists and returns the sum of the two lists.
Example:
def sumOfSums(a: List[Int], b: List[Int]): Int = {
var sum = 0
for(elem <- a) sum += elem
for(elem <- b) sum += elem
sum
}
Simple enough, however now I'm trying to do it recursively and the second list parameter is throwing me off.
What I have so far:
def sumOfSumsRec(a: List[Int], b: List[Int], acc: Int): Int = a match {
case Nil => acc
case h :: t => sumOfSumsRec(t, acc + h)
}
There's 2 problems here:
I'm only matching on the 'a' List
I'm getting an error when I try to do acc + h, im not sure why.
Question: How can I recursively iterate over two lists to get their sum?
Pattern match both lists:
import scala.annotation.tailrec
def recSum(a: List[Int], b: List[Int]): Int = {
#tailrec
def recSumInternal(a: List[Int], b: List[Int], acc: Int): Int = {
(a, b) match {
case (x :: xs, y :: ys) => recSumInternal(xs, ys, x + y + acc)
case (x :: xs, Nil) => recSumInternal(xs, Nil, x + acc)
case (Nil, y :: ys) => recSumInternal(Nil, ys, y + acc)
case _ => acc
}
}
recSumInternal(a, b, 0)
}
Test:
recSum(List(1,2), List(3,4,5))
Yields:
15
Side note:
For any future readers of this post, I assumed this question was prinarly asked for educational purposes mostly, hence showing how recursion can work on multiple lists, but this is by no mean an idiomatic way to take. For any other purposes, by all means:
scala> val a = List(1,2)
a: List[Int] = List(1, 2)
scala> val b = List(3,4,5)
b: List[Int] = List(3, 4, 5)
scala> a.sum + b.sum
res0: Int = 15
Or consider using mechanisms such as foldLeft, foldMap, etc.

Drop a given number of positive items of a given list

Suppose I need a function List[Int] => Option[List[Int]] to drop exactly n elements of a given list if and only if all of them > 0. If the list size <= n the function should return None.
For instance:
def posn(n: Int): List[Int] => Option[List[Int]] = ???
val pos4: List[Int] => Option[List[Int]] = posn(4)
scala> pos4(Nil)
res18: Option[List[Int]] = None
scala> pos4(List(-1))
res19: Option[List[Int]] = None
scala> pos4(List(-1, 2, 3))
res20: Option[List[Int]] = None
scala> pos4(List(1, 2, 3))
res21: Option[List[Int]] = None
scala> pos4(List(1, 2, 3, 4, 5))
res22: Option[List[Int]] = Some(List(5))
scala> pos4(List(1, 2, 3, -4, 5))
res23: Option[List[Int]] = None
I am writing posn like that:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (xs.size >= n && xs.take(n).forall(_ > 0)) Some(xs.drop(n)) else None
This function seems working bit it doesn't seem elegant and idiomatic. How would you re-write it ?
Here's an (arguably) more idiomatic implementation using Pattern Matching and a recursive call to posn - but I'm not sure it's preferable to your suggested implementation:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => (n, xs) match {
case (0, _) => Some(xs) // stop if enough objects dropped
case (_, head :: tail) if head > 0 => posn(n - 1)(tail) // drop positive and move on
case _ => None // found a negative item or end of xs => "fail"
}
I don't know if there is an idiomatic or elegant way to do this. There seems to be no generic pattern that can be extracted from your logic, except what you have already done (using drop and take), so I don't believe you will find some more useful predefined method
However, you are traversing your list a few times, and this could be avoided:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => {
val (head, tail) = xs.splitAt(n) //does take and drop in one run
if (head.lengthCompare(n) == 0 && head.forall(_ > 0)) Some(tail) // lengthCompare does not compute the whole length if there is no need to
else None
}
This is still not perfect, and more verbose than your version.
You could also do all of it at once, with tail recursion (here assuming n>=0):
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (n == 0) Some(xs)
else if (xs.isEmpty || xs.head <= 0) None
else posn(n - 1)(xs.tail)
This would be more efficient if List was naively implemented, but I really doubt you will see any improvement.
I would write a generic version and use that to define posn:
def dropWhen[T](n: Int, p: T => Boolean, l: List[T]): Option[List[T]] = {
val (f, s) = l.splitAt(n)
if (f.length >= n && f.forall(p)) { Some(s) } else { None }
}
def posn(n: Int): List[Int] => Option[List[Int]] = l => dropWhen(n, (i : Int) => i > 0, l)
Note this method scans the prefix of length n twice
Another (non-recursive) alternative: use zipWithIndex and dropWhile to drop the first N positive numbers, and then check head to see whether the first remaining item is exactly at position n: if it is, we got what we want, otherwise we can return None:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
Some(xs.zipWithIndex.dropWhile { case (v, i) => v > 0 && i < n })
.find(_.headOption.exists(_._2 == n)) // first index should be n
.map(_.map(_._1)) // remove indices

Confused about merge sort implementation

What is occurring on this line, x is being concatenated to xs1 but x and xs1 are not defined anywhere?
case (x :: xs1, y :: ys1) =>
Also here, what value do have x and y below? Is merge being recursively called as part of the case class?
if( x < y) x :: merge(xs1 , ys)
Here is the complete Scala code :
object mergesort {
def msort(xs: List[Int]): List[Int] = {
val n = xs.length / 2
if(n == 0) xs
else {
def merge(xs: List[Int], ys: List[Int]): List[Int] = (xs , ys) match {
case (Nil, ys) => ys
case (xs, Nil) => xs
case (x :: xs1, y :: ys1) =>
if( x < y) x :: merge(xs1 , ys)
else y :: merge(xs, ys1)
}
val (fst, snd) = xs splitAt n
merge(msort(fst), msort(snd))
}
} //> msort: (xs: List[Int])List[Int]
val nums = List(2, -4, 5, 7, 1) //> nums : List[Int] = List(2, -4, 5, 7, 1)
msort(nums) //> res0: List[Int] = List(-4, 1, 2, 5, 7)
}
In
case (x :: xs1, y :: ys1) =>
:: is a syntactic sugar in pattern matching to de-construct a list in to head and tail
the list xs is de-constructed in to head x and tail xs.
In pattern matching :: de-constructs' a list, exact reverse of what it actually does in normal, construct a list.
Read De-Constructing objects in The Point of Pattern Matching in Scala
This
(xs , ys) match {
...
case (x :: xs1, y :: ys1)
is a pattern match that declares the variables x, xs1 etc. in the same statement as asserting a sequence match.
The code above is checking that xs can be decomposed into a sequence with head x and tail xs1, and if so, making the head/tail available to the successive code block in those two variables.
To answer your second question (since nobody else has!), yes, the merge function (declared within the outer function) is being called recursively.
Here's an example of how scala allows you to do pattern matching on a List:
scala> List(1,2,3)
res0: List[Int] = List(1, 2, 3)
scala> res0 match {
| case h :: t => "more than two elements, " + h + " is the first"
| case _ => "less than two elements"
| }
res1: java.lang.String = more than two elements, 1 is the first
Note that :: on the left side of the case decomposes the list in its head ( 1 ) and its tail (the rest of the list 2, 3) and binds the values to h and t, that are created and scoped only inside the first case.
Here's how you decompose a tuple:
scala> val tp = ("a", 1)
tp: (java.lang.String, Int) = (a,1)
scala> tp match {
| case (a, b) => a + " is a string, " + b + " is a number"
| case _ => "something missing"
| }
res2: java.lang.String = a is a string, 1 is a number
In the code in your question you're mixing both things and pattern matching on a tuple of Lists (xs , ys).
case (x :: xs1, y :: ys1) is both decomposing the tuple in its two lists and decomposing its two lists in their respective heads and tails.
The match-case keywords are used in scala to perform pattern matching, which is a way to match/decompose objects using several mechanisms like case classes and extractors. Google for scala pattern matching and you'll find the answers you need.