首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Scala列表中的下一个或前一个元素替换某些元素

用Scala列表中的下一个或前一个元素替换某些元素
EN

Stack Overflow用户
提问于 2016-11-02 00:43:40
回答 2查看 141关注 0票数 1

在了解了scala中的一些函数之后,我尝试从list中修补元素:

代码语言:javascript
复制
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应该是:

代码语言:javascript
复制
List[List[Int]] = List(List(7,2,2,5,2),List(7,7,3,3,3),List(7,1,4,4,4))

我尝试了以下代码:

代码语言:javascript
复制
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

你能解释一下有什么区别吗?它是如何工作的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-02 00:52:29

问题就在上一次的比赛模式中:

代码语言:javascript
复制
case x0 :: x1 :: x2 :: x3 :: 8 => List(x0,x1,x2,x3,x3)

您将8放在列表尾的位置,因此它必须具有List[Int]类型(或者编译器告诉您的更一般的GenTraversableOnce类型)。如果您有固定长度的内部列表,则应该将模式更改为最终具有:: Nil

代码语言:javascript
复制
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)

另一种选择是

代码语言:javascript
复制
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被替换)。

代码语言:javascript
复制
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,还有一些其他的边缘情况。因此,下面是一个更通用的模式匹配解决方案:

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2016-11-02 01:24:12

适用于任意长度的xs:

代码语言:javascript
复制
  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
  }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40370772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档