After knowing some function in scala, I've tried to patch the element from list:
val aList: List[List[Int]] = List(List(7,2,8,5,2),List(8,7,3,3,3),List(7,1,4,8,8))
what I want to do is replacing 8 with right neighbour element if the position of 8 is head, otherwise with left neighbour if 8 is tail.
The updated aList should be:
List[List[Int]] = List(List(7,2,2,5,2),List(7,7,3,3,3),List(7,1,4,4,4))
I've tried the following code:
def f(xs: List[Int]) = xs match {
case x0 :: x1 :: x2 :: x3 :: x4 => List(x0,x1,x2,x3,x4)
case 8 :: x1 :: x2 :: x3 :: x4 => List(x1,x1,x2,x3,x4)
case x0 :: 8 :: x2 :: x3 :: x4 => List(x0,x0,x2,x3,x4)
case x0 :: x1 :: 8 :: x3 :: x4 => List(x0,x1,x1,x3,x4)
case x0 :: x1 :: x2 :: 8 :: x4 => List(x0,x1,x2,x2,x4)
case x0 :: x1 :: x2 :: x3 :: 8 => List(x0,x1,x2,x3,x3)
}
aList.flatMap(f)
The type is mismatch since the type is Product with java.io.Serializable
but requred is scala.collection.GenTraversableOnce
Could you please explain what is the difference and how it works?
The problem is just in the last match pattern:
case x0 :: x1 :: x2 :: x3 :: 8 => List(x0,x1,x2,x3,x3)
You put 8
in the position of the list tail, so it has to have the type List[Int]
(or more generally GenTraversableOnce
as the compiler tells you). If you have fixed length inner lists, you should change your patterns to have :: Nil
in the end:
case 8 :: x1 :: x2 :: x3 :: x4 :: Nil => List(x1,x1,x2,x3,x4)
...
case x0 :: x1 :: x2 :: x3 :: 8 :: Nil => List(x0,x1,x2,x3,x3)
An alternative is
case List(8, x1, x2, x3, x4) => List(x1,x1,x2,x3,x4)
...
case List(x0, x1, x2, x3, 8) => List(x0,x1,x2,x3,x3)
Also, your first pattern means that the other ones won't be ever reached, it just leave the list as is.
If your inner lists are not necessarily fixed-size, you need a more generic solution. Clarify, please, if that's the case.
Also, if you want to map List[List[Int]]
to List[List[Int]]
, you should use .map(f)
instead of flatMap
.
I noticed that in your example in the last sub-list you have two 8
s replaced by the left 4
. If you want to achieve this, you can make your function recursive and add a default case (for when all 8
s are replaced).
def f(xs: List[Int]) = xs match {
case 8 :: x1 :: x2 :: x3 :: x4 :: Nil => f(List(x1,x1,x2,x3,x4))
case x0 :: 8 :: x2 :: x3 :: x4 :: Nil => f(List(x0,x0,x2,x3,x4))
case x0 :: x1 :: 8 :: x3 :: x4 :: Nil => f(List(x0,x1,x1,x3,x4))
case x0 :: x1 :: x2 :: 8 :: x4 :: Nil => f(List(x0,x1,x2,x2,x4))
case x0 :: x1 :: x2 :: x3 :: 8 :: Nil => f(List(x0,x1,x2,x3,x3))
case _ => xs
}
But even with these fixes this way f
will cycle on a list with two 8
s in the beginning and some other edge cases. So here is a more generic solution with pattern matching:
def f(xs: List[Int]): List[Int] = {
// if there are only 8s, there's nothing we can do
if (xs.filter(_ != 8).isEmpty) xs
else xs match {
// 8 is the head => replace it with the right (non-8) neighbour and run recursion
case 8 :: x :: tail if x != 8 => x :: f(x :: tail)
// 8 is in the middle => replace it with the left (non-8) neighbour and run recursion
case x :: 8 :: tail if x != 8 => x :: f(x :: tail)
// here tail either starts with 8, or is empty
case 8 :: tail => f(8 :: f(tail))
case x :: tail => x :: f(tail)
case _ => xs
}
}