返回由Zipper中的谓词过滤的流

时间:2015-07-16 19:08:09

标签: scala functional-programming scalaz

我编写的代码使用zipper + comonad找到第一个equilibrium index

import scalaz._
import Scalaz._

val in = NonEmptyList(-7, 1, 5, 2, -4, 3, 0)
in.toZipper
  .cobind { z => z.lefts.sum == z.rights.sum }
  .findNext(identity)
  .map(_.index)

// returns Some(3)
// I would like to return Some(3, 6) or even a scalaz stream?

我如何调整它以返回所有均衡指数而不仅仅是第一个?

4 个答案:

答案 0 :(得分:1)

我想出了这个:

in.toZipper
  .cobind { z => z.lefts.sum == z.rights.sum }
  .toStream
  .zipWithIndex
  .filter(_._1)
  .map(_._2)

但我不认为它的表现非常好(由于子列表的重复总结)

答案 1 :(得分:1)

我无法帮助您使用scalaz解决方案,但找到平衡指数的更简单的解决方案可能是:

def equilibriaIndices(numbers: List[Int]): List[Int] = {
  // sum numbers left side, sum numbers right side, indices equilibiria 
  val startAcc = (0, numbers.sum, List.empty[Int])
  val (_, _, equilibria) = numbers.zipWithIndex.foldLeft(startAcc) { 
    case ((sumLeft, sumRight, indices), (x, index)) => 
      val newIndices = if (sumLeft == sumRight - x) index :: indices else indices
      (sumLeft + x, sumRight - x, newIndices)
  }
  equilibria.reverse
}

哪会给你:

scala> equilibriaIndices(List(-7, 1, 5, 2, -4, 3, 0))
res5: List[Int] = List(3, 6)

答案 2 :(得分:1)

我认为不可能用Zippercobind编写O(n)解决方案。但是,很容易想出一个没有Zipper(但仍然有效)的解决方案:

val in = NonEmptyList(-7, 1, 5, 2, -4, 3, 0).list

val total = in.sum

in
  .scan(0)(_ + _)
  .zip(in)
  .map { case (leftSum, focus) => leftSum == total - leftSum - focus }
  .zipWithIndex
  .filter(_._1)
  .map(_._2)

答案 3 :(得分:0)

我提出了另一个解决方案:

val in = Stream(-7, 1, 5, 2, -4, 3, 0)
val sum = in.scan(0)(_ + _)
val hash = (in zip sum) map { case (e, lsum) => 2*lsum + e }
val target = sum.last
hash.zipWithIndex.collect { case (e, i) if e == target => i }

此解决方案具有O(n)运行时,并且它不依赖于scalaz。

它还具有不必预先计算总和的优点。