scala中的拆分列表基于相邻元素之间的差异

时间:2013-10-26 10:01:57

标签: scala scala-collections

我们如何根据相邻元素之间的差异在scala中拆分列表。例如给定List(1,3,6,10,12,14)和差异3,该函数将返回List(List(1,3),List(6),List(10,12,14))。 / p>

我们可以使用foldLeft来做到这一点吗?我试图创建一个函数

def splitDiff(list:List[Int],diff:Int) = 
     def func(list:List[List[Int]],m:Int):List[List[Int]] = //compare with last element
     list.foldLeft(List(List(0))).foldLeft(func)

但内在功能似乎很难?有什么帮助吗?

4 个答案:

答案 0 :(得分:2)

嗯,我有一个解决方案,但我怀疑一个人可以做得更好:

(test.head :: test).sliding(2).toList.map( (pair: List[Int]) => (pair(1), pair(1) - pair(0)) )
                   .foldLeft(List(List.empty[Int])){ (acc, pair) => 
     if (pair._2 < 3) (pair._1 :: acc.head) :: acc.tail else List(pair._1) :: acc }

请注意,这会产生“双重反转”顺序的结果:

res3: List[List[Int]] = List(List(14, 12, 10), List(6), List(3, 1))

可以通过在函数末尾添加.map(_.reverse).reverse来纠正。

编辑 - 替代尝试:

def func(is: List[Int], diff: Int): List[List[Int]] = {
  def loop(is: List[Int], prev: Int, acc: List[List[Int]]): List[List[Int]] = is match {
    case Nil => acc
    case h :: t if (h - prev < diff) => loop(t, h, (h :: acc.head) :: acc.tail)
    case h :: t => loop(t, h, List(h) :: acc)
  }

  loop(is, is.head, List(List.empty[Int]))
}

再次,给出了双重反转形式的解决方案。

答案 1 :(得分:1)

使用foldLeft的另一个解决方案:

scala> val x = List(1,3,6,10,12,14)
x: List[Int] = List(1, 3, 6, 10, 12, 14)

scala> val y = x.foldLeft((x.head,List[Int](),List[List[Int]]())) 
     ((x,y)=> if((y- x._1) <3) (y,y :: x._2,x._3) else (y,List(y), x._2 :: x._3))
y: (Int, List[Int], List[List[Int]]) = (14,List(14, 12, 10),List(List(6), List(3
, 1)))

scala> val ans = y._2 :: y._3
ans: List[List[Int]] = List(List(14, 12, 10), List(6), List(3, 1))

答案 2 :(得分:0)

请记住,这是未经测试的:

  def splitListDiff(li: List[Int], diff: Int): List[Int] =
        {
          li match {
            case hd :: tl => if (hd - tl < diff) hd :: splitListDiff(tl, diff) else return li ++ splitListDiff(tl, diff)
            case _ => return li
          }
        }

但是你想要一个利用foldleft的解决方案吗?

答案 3 :(得分:0)

以下工作无需额外的倒车。由于OP没有说列表的元素是否总是按升序排列,我认为使用Math.abs也是好的:

def splitDiff(diff: Int)(xs: List[Int]): List[List[Int]] = xs match {
  case Nil      => Nil
  case h :: t   =>
    val head = h :: ((xs zip t) takeWhile {
      case (a,b) => Math.abs(b-a) < diff
    } map (_._2))
    head :: splitDiff(diff)(xs drop head.length)
}

这种方法的缺点是尾巴被反复拉链。但是,这可以通过封装匹配并在开头只压缩一次来轻松避免。