I'm trying to solve problem 13 from here using recursion, but I get an error (which I don't understand).
The problem is:
Given the following list List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
I need to return repeated elements and count:
List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e))
This is my code:
object P13 extends App {
val ls2 = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
println(ls2)
println(encodeDirect(ls2))
def encodeDirect[A](ls: List[A]): List[(Int,A)] = ls match {
case h :: tail => (ls.takeWhile( _ == h ).count(_), h) +: encodeDirect (ls.dropWhile ( _ == h ) )
case Nil => Nil
}
}
This is the error:
P13.scala:18: error: type mismatch;
found : List[(Any, A)]
required: List[(Int, A)]
case h :: tail => (ls.takeWhile( _ == h ).count(_), h) +: encodeDirect
(ls.dropWhile ( _ == h ) )
^
one error found
Why is this happening and how to fix this?
Your mistake is quite simple, you used count instead of size/length:
def encodeDirect[A](ls: List[A]): List[(Int,A)] = ls match {
case h :: tail => (ls.takeWhile( _ == h ).size, h) +: encodeDirect (ls.dropWhile ( _ == h ) )
case Nil => Nil
}
count takes predicate and calculates the number of elements that match that predicate, while size just returns the length of the collection.
Just for fun, here is an alternative, that utilizes span, that breaks collection into prefix/suffix:
def encodeDirect[A](ls: List[A]): List[(Int,A)] =
ls.headOption.map(h => ls.span(h == _)).toList
.flatMap { case (pref, t) => (pref.size, pref.head) :: encodeDirect(t) }
Also it may be a good idea to rewrite this function in tail-recursive way, using results accumulator as an argument, as tail recursion is more efficient in scala.
Another approach, using span,
def encode(xs: List[Symbol]): List[(Int,Symbol)] = xs match {
case Nil => Nil
case x :: xss => val (g,rest) = xs.span(_ == x)
(g.size,g.head) +: encode(rest)
}
where we bisect the list into identical items to the head first, and then the rest.
Related
I need to generate of all combinations of size n from a list of items. I am trying to solve this functionally using recursion. Here is my solution:
def combinations(i: Int, value: List[Symbol]): List[List[Symbol]] = {
if (i == 0) List(Nil)
else if (i == value.size) List(value)
else value match {
case Nil => List(Nil)
case head::tail => {
combinations(i, tail) ::: combinations(i - 1, tail) map { tailCombos => head :: tailCombos }
}
}
}
Here is my test input:
combinations(3, List('a, 'b, 'c, 'd ))
I am getting
List(List('a, 'b, 'c, 'd), List('a, 'b, 'c, 'd), List('a, 'b, 'c, 'd), List('a, 'b, 'c))
instead of
List(List('b, 'c, 'd), List('a, 'b, 'd), List('a, 'c, 'd), List('a, 'b, 'c))
There are other solutions I can refer to, so please don't give me some working solution. However I want to know why my code doesn't work and what needs to be fixed.
It is nothing more than some syntactic confusion. The white space based syntax (there is a name for it but i forgot) was introduced in the early days and has caused nothing but confusion. I highly recommend sticking to the dot syntax.
What is happening is because of the left to right evaluation, map is being applied to the entire result of combinations(i, tail) ::: combinations(i - 1, tail)
instead if you did
combinations(i, tail) ::: combinations(i - 1, tail).map{ tailCombos => head :: tailCombos }
You will get the result you want.
Working scastie --> https://scastie.scala-lang.org/dV3BJ9fIQBSckt1LLTfbrw
P.S. If you are using cats, you can rely on built in combine on semigroups to generate this as well
I want to implement a combination function in scala and my code is as below:
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => List(Nil)
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => List.empty
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
but the result is not what I expect. When I call combination(3, List('a, 'b, 'c, 'd, 'e, 'f). it will give me those results with one or two elements like List('d, 'f), List('f) and so on. Can anyone help me to find the issue? Thanks.
Update:
the correct version is
def combination[A](n: Int, ls: List[A]): List[List[A]] ={
(n, ls) match{
case (_, Nil) => Nil
case (1, _) => ls.map(List(_))
case (_, _) if n > ls.size => Nil
case _ => ls.flatMap(x => combination(n - 1, subList(x, ls)).map(x :: _))
}
}
def subList[A](e: A, in: List[A]) = in.takeRight(in.size - in.indexOf(e) - 1)
Too many cases, unnecessary complicated combinations2 and subList.
Recall how combinations are defined. If you have a set {a1, ..., aN}, and you want to select k elements from this set, then you can do essentially just two things:
You don't include a1 into the subset. Then you have to select k elements from the remaining {a2, ..., aN}.
You include a1 into the subset. Then you have to select k-1 elements from {a2, ..., aN}, and add a0 to those k-1 elements.
That's where the formula
C(N, k) = C(N - 1, k) + C(N - 1, k - 1)
comes from.
Translated into code, this is just:
def comb[A](ls: List[A], k: Int): List[List[A]] = {
if (k == 0) List(Nil)
else ls match {
case Nil => List()
case h :: t => comb(t, k) ++ comb(t, k - 1).map(h :: _)
}
}
Example:
comb(List('a, 'b, 'c, 'd, 'e), 3) foreach println
gives:
List('c, 'd, 'e)
List('b, 'd, 'e)
List('b, 'c, 'e)
List('b, 'c, 'd)
List('a, 'd, 'e)
List('a, 'c, 'e)
List('a, 'c, 'd)
List('a, 'b, 'e)
List('a, 'b, 'd)
List('a, 'b, 'c)
In the last case you are calling combination2. If you change to combination (with reasonable definition of subList) it works. I guess this is something remaining from an intermediate version.
There's a much simpler way of doing this
def comb[A](n: Int, ls:List[A]): List[List[A]] = {
if(ls.isEmpty) List(Nil)
else ls.toSet[A].subsets.map(_.toList).filter(_.length == n).toList
}
Scala fiddle
I'm trying to solve problem 12 taken from here
To summarize, given a list of tuples:
List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))
the result should be a list containing each element in _2 repeated _1 times
The result would be List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
This is my attempt (see code online)
object P12 extends App {
val ls2 = List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))
println(ls2)
println(decode(ls2))
def decode[A] (list: List[(Int,A)]): List[A] = {
list.foldLeft(List[A]()) { (result, elem) => for ( n <- 1 to elem._1) result :+ elem._2 }
}
}
I get the following error:
Main.scala:9: error: type mismatch;
found : Unit
required: List[A]
list.foldLeft(List[A]()) { (result, elem) => for ( n <- 1 to elem._1) result :+ elem._2 }
how to fix this?
Use List.fill and a flatMap:
val l = List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))
l.flatMap { t => List.fill(t._1)(t._2) }
Your for cycle does nothing, are you are using it in imperative way with immutable collection. On each iteration you create new collection from result with appended element and then just discard it. The result of your for is Unit, hence the error.
The correct functional way to perform your task is this:
def decode[A] (list: List[(Int,A)]): List[A] = {
list.foldLeft(List[A]()) { case (result, (count, el)) =>
result ::: (1 to count).map(_ => el).toList
}
}
UPD: Also please note, that append operation on List takes linear time, so the whole decode becomes O(n2).
There is more efficient and concise way to perform your task, using flatMap:
def decode[A](list: List[(Int, A)]): List[A] =
list.flatMap { case (count, el) => (1 to count).map(_ => el) }
This recursive function denotes (or lists) the semantics concisely in two cases,
def decode( xs: List[(Int,Symbol)] ): List[Symbol] = xs match {
case Nil => Nil
case (x :: xss) => List.fill(x._1)(x._2) ++ decode(xss)
}
An empty list results in an empty list, else for the head element of a non empty list, expand it into a list of repeated elements and prepend it to the rest of the decoded list.
I'm working on the following problem:
Pack consecutive duplicates of list elements into sublists. If a list
contains repeated elements they should be placed in separate sublists.
Example:
scala> pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e,
'e)) res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b),
List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))
I am wondering whether it can be implemented using foldRight. So far I can only make a recursive solution like below work:
def pack(list: List[Char]) = {
def checkNext(a: List[List[Char]], prev: Char, l: List[Char]): List[List[Char]] = l match {
case Nil => a
case h::tail if h == prev => checkNext((h::a.head)::a.tail,h,tail)
case h::tail => checkNext(List(h)::a,h,tail)
}
checkNext(List(List[Char](list.last)), list.last, list.init.reverse)
}
Absolutely! I find it to be very natural to use folds to accumulate a complex result from iterating a sequence. Essentially, it works the same as what you're doing now, except the matching on the list is provided to you by fold, and you just provide the processing for the cases. I'm not sure if you wanted an actual answer, so I'll try to give you a couple hints.
Think of the type of your final result. Now think of what value of that type would be the result of applying your process to an empty sequence. That's your first argument to foldRight/foldLeft.
Now you have to define what to do to extend your accumulator for each item you process. It seems to me you have two cases: either you've encountered a new letter that you haven't seen before or you're adding another instance to an existing list. You can use some fancy matching to detect which case you're in.
Here's how I'd do it:
def pack(list: List[Char]) = list.foldLeft(List.empty[List[Char]]) { case (acc, next) =>
acc.headOption.flatMap(_.headOption) match {
case Some(x) if x == next => (acc.head :+ next) +: acc.tail
case _ => List(next) +: acc
}
}.reverse
I used flatMap to join the two checks for whether there's a list at all yet and whether the a list for the current character exists. I find foldLeft to be more intuitive and it also has the added benefit of being tail recursive on List.
The result:
scala> pack(List('a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd',
'e', 'e', 'e', 'e'))
res1: List[List[Char]] = List(List(a, a, a, a),
List(b), List(c, c), List(a, a), List(d), List(e, e, e, e))
Here is my version of fold:
def pack[A](xs: List[A]): List[List[A]] =
xs.foldRight(List[List[A]]()){
case (x, (ys#(y::_)) :: rs) if x == y => (x::ys) :: rs
case (x, ys) => List(x) :: ys
}
However, I prefer the recursive one:
def pack2[A](xs: List[A]): List[List[A]] = xs match {
case Nil => Nil
case x::_ => val (hs, ts) = xs.span(x==); hs::pack2(ts)
}
The recursive one is clearer and shorter than the fold version, in addition it is faster!
scala> def time(n: Int)(call : => Unit): Long = {
| var cnt = 0
| val start = System.currentTimeMillis
| while(cnt < n) {
| cnt += 1
| call
| }
| System.currentTimeMillis - start
| }
time: (n: Int)(call: => Unit)Long
scala> val xs = ("A"*100 + "B"*1000 + "C"*10 + "DEFGH"*1000).toList
xs: List[Char] = List(A, A, A...)
scala> time(10000){ pack(xs) }
res3: Long = 19961
scala> time(10000){ pack2(xs) }
res4: Long = 4382
And named #acjay's version as pack3:
scala> def pack3(list: List[Char]) = list.foldLeft(List.empty[List[Char]]) { case (acc, next) =>
| acc.headOption.flatMap(_.headOption) match {
| case Some(x) if x == next => (acc.head :+ next) +: acc.tail
| case _ => List(next) +: acc
| }
| }.reverse
pack3: (list: List[Char])List[List[Char]]
scala> time(10000){ pack3(xs) }
res5: Long = 420946
scala> pack3(xs) == pack2(xs)
res6: Boolean = true
scala> pack3(xs) == pack(xs)
res7: Boolean = true
Implementation by Martin Odersky
def pack[T](xs: List[T]): List[List[T]] = xs match{
case Nil => Nil
case x :: xs1 =>
val (first, rest) = xs span (y => y == x)
first :: pack(rest)
}
I'm trying to solve the problem 12 of S-99: Ninety-Nine Scala Problems
Given a run-length code list generated as specified in problem P10,
construct its uncompressed version. Example:
scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
I was trying to pattern match the element in the list and then use a for loop to concatenate the char but I've got the following compilation error on line 5 :
type mismatch; found : scala.collection.immutable.IndexedSeq[List[A]] required: List[A]
1 def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
2 case Nil => Nil
3 case x :: xs => {
4 for {
5 i <- 1 to x._1
6 } yield (x._2) :: decode(xs)
7 }
8 }
Sorry but I begin Scala. Could someone explain why this is happening and how to solve it ?
You are quite close - just a couple of problems. Here is a fixed version I came up with:
def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
case Nil => Nil
case x :: xs => (for {
i <- 1 to x._1
} yield (x._2)).toList ::: decode(xs)
}
The first - and probably most important - thing is the extra parentheses around the for-yield. Without this, you are trying to yield (x._2) :: decode(xs), rather than just (x._2) (to make up for that, the {} around the whole case can be omitted).
Next, the for-yield results in an IndexedSeq rather than a List, so I forced a conversion to List (you could handle this in various ways, this was merely the most expedient).
Finally, concatenating to the List resulting from decode(xs) requires the ::: operator (you can also use ++) rather than :: (which prepends a single entry, not a sub-list).
The main issue is the operator you use for concatenating lists - :: is used only to prepend a single element to a list, so in your code you are trying to prepend the result of the yield (which is itself a sequence) to a List[A] and get type incompatibility as a result. Here is a modified version that will work - it uses operator ++: which can be used to join two sequences together. I also moved the yield to a separate statement, otherwise you would need parentheses around the yield so that ++: works on the complete result of the yield and not on each element (which would again not compile due to types not matching).
def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
case Nil => Nil
case x :: xs => {
val repeatedElems = for {
i <- 1 to x._1
} yield (x._2)
repeatedElems ++: decode(xs)
}
}
The other answers are perfectly fine but I think generating the decoded lists with List.fill requires less syntax and is easier to understand compared to the for-yield expression.
def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
case Nil => Nil
case x :: xs => List.fill(x._1)(x._2) ::: decode(xs)
}
Output:
scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
Here is a slightly modified version of Brian's answer. Decomposing the tuple makes the code even more readable:
def decode[A](xs: List[(Int, A)]) : List[A] = xs match {
case Nil => Nil
case (count, letter) :: xs => List.fill(count)(letter) ::: decode(xs)
}
Another method is using map:
def decode[A](l: List[(Int, A)]): List[A] = {
val l1: List[List[A]] = l map { e =>
List.fill(e._1)(e._2)
}
l1.flatten
}