在了解scala中的某些函数后,我尝试从列表中修补元素:
<div>
我想要做的是如果8的位置是头部则用右邻居元素替换8,否则如果8是尾部则用左邻居替换。
更新后的aList应为:
val aList: List[List[Int]] = List(List(7,2,8,5,2),List(8,7,3,3,3),List(7,1,4,8,8))
我尝试过以下代码:
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
请您解释一下有什么区别以及它是如何工作的?
答案 0 :(得分:1)
问题出在上一个匹配模式中:
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
s和一些其他边缘情况。所以这是一个更通用的模式匹配解决方案:
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
}
}
答案 1 :(得分:1)
适用于任何长度的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
}