6

Traversable[_]コレクションとスワップするインデックスを指定して、任意の で機能する機能的なスワップ関数を作成する方法を見つけようとしていました。私は次のことを思いつきました:

def swap[A, CC <% Traversable[A]](xs: CC, i: Int, j: Int): Traversable[A] = {
  xs.slice(0, i) ++ 
    xs.slice(j, j+1) ++ 
    xs.slice(i+1, j) ++ 
    xs.slice(i, i+1) ++ 
    xs.slice(j+1, xs.size)
}

swap(List(1,2,3,4,5), 0, 4) // => List(5,2,3,4,1)

これを Traversable の暗黙的な拡張にして、 で呼び出せるようにする方法を知りたいですList(1,2,3,4,5).swap(0, 4)。私が得ることができた最も近いものは次のとおりでした:

import language.implicitConversions
class RichTraversable[A, B <% Traversable[A]](xs: B) {
  def swap(i: Int, j: Int): Traversable[A] = {
    xs.slice(0, i) ++ 
      xs.slice(j, j+1) ++ 
      xs.slice(i+1, j) ++ 
      xs.slice(i, i+1) ++ 
      xs.slice(j+1, xs.size)
  }
} 
implicit def richTraversable[A, B <% Traversable[A]](ys: B)(implicit b: Traversable[A])
  = new RichTraversable[A, B](ys)

残念ながらそれだけではありません。を呼び出すList(1,2,3,4,5).swap(0, 4)と、次のエラーが発生します。

エラー: List[Int] => Traversable[A] から利用可能な暗黙的なビューはありません

何かが欠けているか、問題を非常に複雑にしているに違いないと感じています。これがどのように構成されるべきか誰かが知っていますか?


注: これは純粋に学術的なものであり、実稼働環境では決して使用されていません。Scala の型システムと境界をうまく扱えるようにしています。

4

1 に答える 1

4

Scala 2.10 を使用している場合:

import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike

implicit class TraversableWithSwap[A, Repr <: Traversable[A]](val xs: TraversableLike[A, Repr]) extends AnyVal {
  def swap[That](i: Int, j: Int)(implicit bf: CanBuildFrom[Repr, A, That]): That = {
    val builder = bf(xs.asInstanceOf[Repr])
    builder.sizeHint(xs)
    builder ++= xs.take(i)
    builder ++= xs.slice(j, j + 1)
    builder ++= xs.slice(i + 1, j)
    builder ++= xs.slice(i, i + 1)
    builder ++= xs.drop(j + 1)
    builder.result
  }
}

(AnyVal事はそれを値クラスに変えます。つまり、コンパイラはそれを静的関数として書き直して、実行時に実際にラッピングを行うことを回避します。)

以前のバージョンを使用している場合は、 を削除して、extends AnyVal代わりに暗黙的な変換関数を使用しますimplicit class

implicit def toTraversableWithSwap[A, Repr <: Traversable[A]](xs: TraversableLike[A, Repr]) = new TraversableWithSwap(xs)

そしてそれを使用して:

scala> Vector(1,2,3,4,5,6,7,8,9).swap(2,5)
res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 6, 4, 5, 3, 7, 8, 9)

Traversable一部のトラバーサブル ( SetMapなど) は順序付けされていないため、この関数をすべてに対して定義することは実際には意味がないことに注意してください。したがって、2 つの要素を交換しても意味がありません。Seqおそらく、実際にはすべてまたは何かに対して定義したいと思うでしょう。

また、「enhance-my-library」と呼ぶことに同意できますか?

于 2013-03-29T19:19:12.897 に答える