【问题标题】:split list in scala based on diff between neighbouring elements基于相邻元素之间的差异在scala中拆分列表
【发布时间】:2013-10-26 10:01:56
【问题描述】:

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

我们可以使用 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)

但是内部函数似乎很难?有什么帮助吗?

【问题讨论】:

  • 不清楚:你在 3 (6 - 3 = 3) 之后分裂,但你也在 6 (10 - 6 = 4) 之后分裂
  • 对不起,我的意思是如果 diff >= 3,我就分开了

标签: scala scala-collections


【解决方案1】:

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

(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]))
}

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

【讨论】:

  • 坦率地说是你的解决方案,但它看起来比它需要的要复杂一些 =)
  • 确实,@Stefan Kunze。我尝试了另一种看起来更好的尝试 - 事实上,看起来与您的解决方案非常相似!
  • 哈哈,我没费心去创建一个列表:)只是把原理图布置好了。
  • 实际上,我有点惊讶 List(或者更确切地说,TraversableLike)上没有类似于现有的partition 的方法,但是将序列多次划分为通过 -满足布尔条件(partition 仅将列表划分一次)。如果我有几个类似的计算要做,我可能会先看看拉皮条这样的方法。
  • 我最初的想法也是使用分区。一定有一种简单的方法可以将其抬起。
【解决方案2】:

另一种使用 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))

【讨论】:

    【解决方案3】:

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

      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 的解决方案?

    【讨论】:

      【解决方案4】:

      以下工作无需额外的反转。由于 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)
      }
      

      这种方法的缺点是尾巴会一遍又一遍地拉上拉链。但是,可以通过封装匹配项并在开始时仅压缩一次来轻松避免这种情况。

      【讨论】:

        猜你喜欢
        • 2019-08-19
        • 2012-06-21
        • 2014-03-09
        • 1970-01-01
        • 2021-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多