使用每个元素的增量阴影计算集合中每个元素的函数的最佳方法是什么,例如这个简单的示例:
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)
我认为首先要patch
或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)
我认为首先要patch
或slice
要做到这一点,但也许有更好的纯功能风格来做到这一点?
谢谢先生。
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
}
你可以这样定义它:
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)
如果“纯功能风格”的意思是“不参考索引”(因为你说你想避免patch
and ),你可以用zippersslice
优雅地做到这一点。例如,这里是如何用Scalaz 的 zipper 实现编写它(这只是一个演示——如果你想把它包装得更好,你可以使用 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 的解决方案可能会更好,但 zipper 是一个方便了解的数据结构,它非常适合这个问题。