The function below generates a List
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x::xs =>
val (first, rest) = xs span(y => y==x)
first::pack(rest)
}
When applying pack on a list
val lis4 = List("a", "a", "a", "b", "c", "c", "a")
I get a result
res3: List[List[String]] = List(List(a, a), List(), List(c), List())
However, according to the course given by Martin Odersky on coursera,
it should generate a result
Can anyone tell me what's wrong?
You're shadowing xs defined at the method level with the local binding of xs inside the pattern match. Notice in Oderskys example, the local pattern match bind is called xs1:
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)
}
To make this even clearer, you can ignore the tail part of the list in the pattern match using _:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x :: _ =>
val (first, rest) = xs span(y => y == x)
first :: pack(rest)
}
Yields:
scala> pack(List("a", "a", "a", "b", "c", "c", "a"))
res2: List[List[String]] = List(List(a, a, a), List(b), List(c, c), List(a))
Related
I want a recursive function, which removes the consecutive elements "one" and "a".
Is there a way, that i can treat head as a list, like tail, so it doesn't matter where in the list "one" and "a" occures?
def reduc(list: List[String]): List[String] = {
list match {
case "one" :: "a" :: tail => reduc(tail)
case head :: "one" :: "a" :: tail => reduc(head :: tail)
case _ => list
}
}
reduc(List("one", "one", "a", "a", "b", "c", "one", "a", "c")).mkString(" ")```
expected output:
b c c
actual:
b c one a c
It can be done without pattern matching.
def reduc(list: List[String]): List[String] = {
val index = list.indexOfSlice(List("one","a"))
if (index < 0) list
else reduc(list.patch(index,List(),2))
}
testing:
reduc(List("one", "one", "a", "a", "b", "c", "one", "a", "c"))
//res0: List[String] = List(b, c, c)
A tail recursive version using pattern matching and an extra parameter as #Luis noted in comments to accumulate the results:
def reduc(list: List[String]): List[String] = {
def reducR(list: List[String], acc: List[String]): List[String] = list match {
case Nil => acc
case head::tail if(head != "a" && head != "one") => reducR(tail, head::acc)
case head::tail => reducR(tail, acc)
}
reducR(list, List()).reverse
}
How can i achieve this? Where xs is a List[Any].
def flatten(xs: List[Any]): List[Any] = {
xs match {
case x: List[Any] :: t => flatten(x) ::: flatten(t)
case x :: t => x :: flatten(t)
case Nil => Nil
}
}
The first case does not work properly. For some reason I cannot give a type to the head of the list x.
As #Luis mentioned, this is really bad idea to use List[Any] but you still want to write flatten, then using reflection you can do like this:
val xs: List[Any] = List(List(1, 2), 3, 4)
def flatten(xs: List[Any]): List[Any] = {
xs match {
case x :: t if x.isInstanceOf[List[_]] => flatten(x.asInstanceOf[List[Any]]) ::: flatten(t)
case x :: t => x :: flatten(t)
case Nil => Nil
}
}
println(flatten(xs)) // List(1, 2, 3, 4)
IntelliJ complains the "Expression of type List[Any] doesn't conform to expected type List[T]" on the line first :: pack(rest).
val data = List("a", "a", "a", "b", "c", "c", "a")
def pack[T](xs: List[T]): List[T] = xs match {
case Nil => Nil
case x :: xs1 =>
val (first, rest) = xs span (y => y == x)
first :: pack(rest)
}
pack(data)
When pattern match found the original list is a not Nil, it will have least one member. That is x :: xs1. When span is applied on the original list with the condition y => y == x, it should return a List. In this example, for the first found character 'a', it should return List(a,a,a) which then match the first.
I couldn't figure out why Scala complained.
The objective is to have a list
List(List(a, a, a), List(b), List(c, c), List(a))
P.S.
My return type is wrong it should be List[List[T]]. thanks for all your help.
Now that you have clarified the requirement. You want to have List(List(a, a, a), List(b), List(c, c), List(a)) as output for an input List("a", "a", "a", "b", "c", "c", "a").
The thing is that Nil by itself is of type scala.collection.immutable.Nil.type so the overall return type of your pack function is being interpreted as List[Any].
So, replace case Nil => Nil by List[T]() and first :: pack(rest) by x :: pack(rest).
Also,y => y == x is not safe to compare objects, replace this by y => y.equals(x).
val data = List("a", "a", "a", "b", "c", "c", "a")
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => List.empty[List[T]]
case x :: xs1 => {
val (first, rest) = xs.span(t => t.equals(x))
first :: pack(rest)
}
}
pack(data)
val data = List("a", "a", "a", "b", "c", "c", "a")
def pack[T](xs: List[T]): List[List[T]] = {
def helper(map: Map[T, Int])(xs: List[T]): Map[T, Int] = xs match {
case Nil => map
case x :: xs =>
if (map contains x) {
helper(map + (x -> (map(x) + 1)))(xs)
} else {
helper(map + (x -> 1))(xs)
}
}
helper(Map.empty[T, Int])(xs).map { case (x, count) => List.fill(count)(x) }.toList
}
println(pack(data))
scala> println(pack(data))
List(List(a, a, a, a), List(b), List(c, c))
I worked on the "Pack Function" exercise from "Functional Programming Principles in Scala".
Put consecutive duplicates into a List[List[T]].
Example
input: List("a", "a", "b", "b", "c", "a")
output: List(List(a, a), List(b, b), List(c), List(a))
Given this function...
def pack[T](xs: List[T]): List[List[T]] = {
def go[T](ys: List[T], acc: List[List[T]]) : List[List[T]] = ys match {
case Nil => acc
case x :: xs_ => val r: List[T] = ys.takeWhile(a => a == x)
go(ys.drop(r.length), acc :+ r)
}
go(xs, List(Nil).filter(_ != Nil)) // *** line in question ***
}
Is there a better way to pass in a List[List[T]] where the inner list is empty?
If I didn't have the filter there, the head of pack(...)'s result would be List().
Why not just...........:
go(xs, Nil)
BTW, there is my solution for this problem:
def pack[T](xs: List[T],
acc: List[List[T]] = Nil): List[List[T]] =
(xs, acc) match {
case (Nil, _) => acc
case (i:+last, (h::t1)::t2) if last == h => pack(i, (last::h::t1)::t2)
case (i:+last, acc0) => pack(i, List(last)::acc0)
}
And here is another solution:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x::rs => pack(rs) match {
case (h#`x`::_)::t => (x::h)::t
case t => List(x)::t
}
}
I want to write a function that flattens a List.
object Flat {
def flatten[T](list: List[T]): List[T] = list match {
case Nil => Nil
case head :: Nil => List(head)
case head :: tail => (head match {
case l: List[T] => flatten(l)
case i => List(i)
}) ::: flatten(tail)
}
}
object Main {
def main(args: Array[String]) = {
println(Flat.flatten(List(List(1, 1), 2, List(3, List(5, 8)))))
}
}
I don't know why it don't work, it returns List(1, 1, 2, List(3, List(5, 8))) but it should be List(1, 1, 2, 3, 5, 8).
Can you give me a hint?
You don't need to nest your match statements. Instead do the matching in place like so:
def flatten(xs: List[Any]): List[Any] = xs match {
case Nil => Nil
case (head: List[_]) :: tail => flatten(head) ++ flatten(tail)
case head :: tail => head :: flatten(tail)
}
My, equivalent to SDJMcHattie's, solution.
def flatten(xs: List[Any]): List[Any] = xs match {
case List() => List()
case (y :: ys) :: yss => flatten(y :: ys) ::: flatten(yss)
case y :: ys => y :: flatten(ys)
}
By delete line 4
case head :: Nil => List(head)
You will get right answer.
Think about the test case
List(List(List(1)))
With line 4 last element in list will not be processed
def flatten(ls: List[Any]): List[Any] = ls flatMap {
case ms: List[_] => flatten(ms)
case e => List(e)
}
If someone does not understand this line of the accepted solution, or did not know that you can annotate a pattern with a type:
case (head: List[_]) :: tail => flatten(head) ++ flatten(tail)
Then look at an equivalent without the type annotation:
case (y :: ys) :: tail => flatten3(y :: ys) ::: flatten3(tail)
case Nil :: tail => flatten3(tail)
So, just for better understanding some alternatives:
def flatten2(xs: List[Any]): List[Any] = xs match {
case x :: xs => x match {
case y :: ys => flatten2(y :: ys) ::: flatten2(xs)
case Nil => flatten2(xs)
case _ => x :: flatten2(xs)
}
case x => x
}
def flatten3(xs: List[Any]): List[Any] = xs match {
case Nil => Nil
case (y :: ys) :: zs => flatten3(y :: ys) ::: flatten3(zs)
case Nil :: ys => flatten3(ys)
case y :: ys => y :: flatten3(ys)
}
val yss = List(List(1,2,3), List(), List(List(1,2,3), List(List(4,5,6))))
flatten2(yss) // res2: List[Any] = List(1, 2, 3, 1, 2, 3, 4, 5, 6)
flatten3(yss) // res2: List[Any] = List(1, 2, 3, 1, 2, 3, 4, 5, 6)
By the way, the second posted answer will do the following, which you probably don't want.
val yss = List(List(1,2,3), List(), List(List(1,2,3), List(List(4,5,6))))
flatten(yss) // res1: List[Any] = List(1, 2, 3, List(), 1, 2, 3, 4, 5, 6)