使用这些集合中元素的增量阴影计算每个元素的函数的最佳方法

时间:2012-07-24 17:25:16

标签: scala collections map slice

使用每个元素的增量阴影计算集合中每个元素的函数的最佳方法是什么,如下这个简单示例:

val v = IndexedSeq(1,2,3,4)

v.shadowMap{ e => e + 1}

shadow 1: (3,4,5)
shadow 2: (2,4,5)
shadow 3: (2,3,5)
shadow 4: (2,3,4)

我首先想到patchslice来实现这个目标,但也许有更好的方法可以用纯粹的功能风格来做到这一点?

由于 SR。

3 个答案:

答案 0 :(得分:3)

def shadowMap[A,B](xs: Seq[A])(f: A => B) = {
  val ys = xs map f
  for (i <- ys.indices; (as, bs) = ys splitAt i) yield as ++ bs.tail
}

答案 1 :(得分:2)

您可以这样定义:

class ShadowMapSeq[A, Repr <: Seq[A]](seq: SeqLike[A, Repr]) {
  def shadowMap[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): Iterator[That] = {
    seq.indices.iterator.map { i =>
      val b = bf(seq.asInstanceOf[Repr])
      b.sizeHint(seq.size - 1)
      b ++= (seq.take(i) ++ seq.drop(i + 1)).map(f)
      b.result
    }
  }
}
implicit def shadowMapSeq[A, Repr <: Seq[A]](seq: SeqLike[A, Repr]) = new ShadowMapSeq(seq)

然后像这样使用它:

scala> val v = IndexedSeq(1, 2, 3, 4)
scala> val results = v.shadowMap(_ + 1)
scala> results foreach println
Vector(3, 4, 5)
Vector(2, 4, 5)
Vector(2, 3, 5)
Vector(2, 3, 4)

答案 2 :(得分:1)

如果采用纯粹的功能风格&#34;你的意思是&#34;没有引用索引&#34; (因为你说你想避免patchslice),你可以用zippers非常优雅地做到这一点。例如,以下是如何使用Scalaz's zipper implementation编写它(这只是一个演示 - 如果你想更好地包装它,你可以使用dhg在他的答案中给出的方法):

import scalaz._, Scalaz._

List(1, 2, 3, 4).map(_ + 1).toZipper.map(
   _.positions.map(p => (p.lefts.reverse ++ p.rights).toList).toStream
).flatten

一般情况下,您可能最好使用dhg的实际代码解决方案,但拉链是一个方便的数据结构,并且它非常适合这个问题。< / p>