Pattern Matching List[Any] with nested lists Scala? - scala

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)

Related

Case with no return value

I have the following unit test:
FlattenArray.flatten(
List(0, 2, List(List(2, 3), 8, List(List(100)), null, List(List(null))), -2))
should be(List(0, 2, 2, 3, 8, 100, -2))
With my implementation as follow:
object FlattenArray {
def flatten(list: List[Any]): List[Any] = {
list match {
case Nil => Nil
case (x: List[Any]) :: tail => flatten(x) ::: flatten(tail)
case x :: tail => x :: flatten(tail)
}
}
}
The test if failing because, on case Nil I should add no value to the flatten list: any suggestion on how to do so?
I could filter out from the flatten list null values: is that the correct implementation?
You can add a special case for null :: tail which returns flatten(tail):
def flatten(list: List[Any]): List[Any] = {
list match {
case Nil => Nil
case null :: tail => flatten(tail)
case (x: List[Any]) :: tail => flatten(x) ::: flatten(tail)
case x :: tail => x :: flatten(tail)
}
}

Any convention for "given an empty list return an empty list" when matching patterns?

When pattern matching a list, it seems common to return an empty list when given an empty list. We can match an empty list to Nil or List(), but we can return empty as Nil, List() or by returning the given list argument itself.
What's the convention here?
When would you choose one method over another?
Examples:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case List() => Nil
case x :: xs => ???
}
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
def givenEmptyNumsReturnsNums(nums: List[Int]): List[Int] = nums match {
case List() => nums
case x :: xs => ???
}
I'm scala beginner and don't know any existing convention about it. My things about it:
The last one isn't intuitive
I prefer return that I match. If I have case List(), so I return List().
You can also match Nil:
-
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
But Nil and List() are the same.
For choice better way, just clarify what inside:
case N1:
def givenEmptyNumsReturnsEmptyList(nums: List[Int]): List[Int] = nums match {
case List() => List()
case x :: xs => ???
}
Will call unaplay method from object List, after will call apply method of object List.
case N2:
def givenEmptyNumsReturnsNil(nums: List[Int]): List[Int] = nums match {
case Nil => Nil
case x :: xs => ???
}
Will compare value before match with object Nil and will return object Nil
And in case of choice I prefer case N2 because it is little bit optimal.

Scala method definition named parameters vs. unnamed

i'm new to Scala and i'm struggling sometimes with method signatures.
Lets take this code, i'm especially interested in naming the parameters to do further operations on them.
def divide(xs: List[Int]): List[Int] = {
val mid = xs.length/2
(xs take mid, xs drop mid)
}
Here I defined the input list named as "xs", I've seen this convention on many web pages. But in university we had another method signature definition method (I am missing the name, sorry) in which we didn't name the input parameter(s) but pattern matching takes place:
def mylength: List[Any] => Int = {
case Nil => 0
case x::xs => mylength(xs)+1
}
In this case, it is very trivial to identify the input parameter because there is just a single one. How could I use the same style as in the code below with 2 or more input parameters in the coding style shown above?
def myConcat(xs: List[Any], ys: List[Any]) = {
xs ++ ys
}
Sorry for my English. I didn't find anything on google because I didn't relly have a clue what terms to search for...
Edit: I have to stick to an interface. I make another example with which you could help me.
myAppend1 and myAppend2 shall behave the same way, putting a new element in the front of the list.
def myAppend1(xs: List[Any], y: Any): List[Any] = {
y :: xs
}
My problem is now the naming of my inputs in myAppend2...
def myAppend2: List[Any] => Any => List[Any] = {
/* how can i do this here, when no names y/xs are given?*/
}
To use the same style with 2 or more parameters, just treat the parameters as a tuple of two:
def myConcat: (List[Any], List[Any]) => List[Any] = {
case (Nil, Nil) => List()
case (xs,ys) => ...
}
Let's take the myAppend example:
def myAppend2: (List[Any], Any) => List[Any] = {
case (xs, y) => y :: xs
}
This has (more or less) the same signature as:
def myAppend1(xs: List[Any], y: Any): List[Any] = {
y :: xs
}
Usage:
scala> myAppend1(List(1,2,3), 4)
res3: List[Any] = List(4, 1, 2, 3)
scala> myAppend2(List(1,2,3), 4)
res4: List[Any] = List(4, 1, 2, 3)
If you had a higher-order function that wanted a function argument of (List[Any], Any) = List[Any], then both will work and are (for most practical purposes) equivalent.
Note that by defining it like
def myAppend3: List[Any] => Any => List[Any] = {
xs => y => y::xs
}
you will be creating a curried function, which in scala has a different signature
(from what you want):
myAppend3(List(1,2,3), 4) // won't compile
myAppend3(List(1,2,3))(4) // need to do this
def myAppend2: List[Any] => Any => List[Any] = { xs => y =>
y :: xs
}
with full form of function literal syntax:
def myAppend2: List[Any] => Any => List[Any] = {
(xs: List[Any]) => {
(y: Any) => {
y :: xs
}
}
}

Scala flatten a List

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)

Scala List function for grouping consecutive identical elements

Given e.g.:
List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
I'd like to get to:
List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))
I would assume there is a simple List function that does this, but am unable to find it.
This is the trick that I normally use:
def split[T](list: List[T]) : List[List[T]] = list match {
case Nil => Nil
case h::t => val segment = list takeWhile {h ==}
segment :: split(list drop segment.length)
}
Actually... It's not, I usually abstract over the collection type and optimize with tail recursion as well, but wanted to keep the answer simple.
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
Here's another way.
(List(xs.take(1)) /: xs.tail)((l,r) =>
if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
Damn Rex Kerr, for writing the answer I'd go for. Since there are minor stylistic differences, here's my take:
list.tail.foldLeft(List(list take 1)) {
case (acc # (lst # hd :: _) :: tl, el) =>
if (el == hd) (el :: lst) :: tl
else (el :: Nil) :: acc
}
Since the elements are identical, I didn't bother reversing the sublists.
list.foldRight(List[List[Int]]()){
(e, l) => l match {
case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
case _ => List(e) :: l
}
}
Or
list.zip(false :: list.sliding(2).collect{case List(a,b) => a == b}.toList)
.foldLeft(List[List[Int]]())((l,e) => if(e._2) (e._1 :: l.head) :: l.tail
else List(e._1) :: l ).reverse
[Edit]
//find the hidden way
//the beauty must be somewhere
//when we talk scala
def split(l: List[Int]): List[List[Int]] =
l.headOption.map{x => val (h,t)=l.span{x==}; h::split(t)}.getOrElse(Nil)
I have these implementations lying around from working on collections methods. In the end I checked in simpler implementations of inits and tails and left out cluster. Every new method no matter how simple ends up collecting a big tax which is hard to see from the outside. But here's the implementation I didn't use.
import generic._
import scala.reflect.ClassManifest
import mutable.ListBuffer
import annotation.tailrec
import annotation.unchecked.{ uncheckedVariance => uV }
def inits: List[Repr] = repSequence(x => (x, x.init), Nil)
def tails: List[Repr] = repSequence(x => (x, x.tail), Nil)
def cluster[A1 >: A : Equiv]: List[Repr] =
repSequence(x => x.span(y => implicitly[Equiv[A1]].equiv(y, x.head)))
private def repSequence(
f: Traversable[A #uV] => (Traversable[A #uV], Traversable[A #uV]),
extras: Traversable[A #uV]*): List[Repr] = {
def mkRepr(xs: Traversable[A #uV]): Repr = newBuilder ++= xs result
val bb = new ListBuffer[Repr]
#tailrec def loop(xs: Repr): List[Repr] = {
val seq = toCollection(xs)
if (seq.isEmpty)
return (bb ++= (extras map mkRepr)).result
val (hd, tl) = f(seq)
bb += mkRepr(hd)
loop(mkRepr(tl))
}
loop(self.repr)
}
[Edit: I forget other people won't know the internals. This code is written from inside of TraversableLike, so it wouldn't run out of the box.]
Here's a slightly cleaner one:
def groupConsequtive[A](list: List[A]): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
(head :: t1) :: groupConsequtive(t2)
case _ => Nil
}
tail-recursive version
#tailrec
def groupConsequtive[A](list: List[A], acc: List[List[A]] = Nil): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
groupConsequtive(t2, acc :+ (head :: t1))
case _ => acc
}
Here's a tail-recursive solution inspired by #Kevin Wright and #Landei:
#tailrec
def sliceEqual[A](s: Seq[A], acc: Seq[Seq[A]] = Seq()): Seq[Seq[A]] = {
s match {
case fst :: rest =>
val (l, r) = s.span(fst==)
sliceEqual(r, acc :+ l)
case Nil => acc
}
}
this could be simpler:
val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values