在了解了scala中的一些函数之后,我尝试从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))我想做的是,如果8的位置是头,则用右邻元素代替8,如果8是尾,则用左邻代替。
更新后的aList应该是:
List[List[Int]] = List(List(7,2,2,5,2),List(7,7,3,3,3),List(7,1,4,4,4))我尝试了以下代码:
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)类型不匹配,因为类型是Product with java.io.Serializable,但请求的是scala.collection.GenTraversableOnce。
你能解释一下有什么区别吗?它是如何工作的?
发布于 2016-11-02 00:52:29
问题就在上一次的比赛模式中:
case x0 :: x1 :: x2 :: x3 :: 8 => List(x0,x1,x2,x3,x3)您将8放在列表尾的位置,因此它必须具有List[Int]类型(或者编译器告诉您的更一般的GenTraversableOnce类型)。如果您有固定长度的内部列表,则应该将模式更改为最终具有:: Nil:
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)另一种选择是
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)此外,您的第一个模式意味着其他模式将永远不会到达,它只是保持原样。
如果您的内部列表不一定是固定大小的,则需要一个更通用的解决方案。请澄清,如果是这样的话。
另外,如果您想将List[List[Int]]映射到List[List[Int]],则应该使用.map(f)而不是flatMap。
编辑
我注意到,在最后一个子列表中的示例中,有两个8被左4替换。如果您想要做到这一点,您可以使您的函数递归,并添加一个默认的情况(当所有的8被替换)。
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
}但是,即使有了这些修复,f也会循环到一个列表上,其中开头有两个8,还有一些其他的边缘情况。因此,下面是一个更通用的模式匹配解决方案:
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
}
}发布于 2016-11-02 01:24:12
适用于任意长度的xs:
def f(xs: List[Int]) = {
if (xs.length <= 1) xs else
(for {
i <- 0 until xs.length
} yield {
xs(i) match {
case 8 => if (i == 0) xs(1) else xs(i - 1)
case _ => xs(i)
}
}).toList
}https://stackoverflow.com/questions/40370772
复制相似问题