7

演習として、Scala Arrayコレクションを自分のOneBasedArrayに拡張したいと思います(期待どおりの動作をします。インデックス作成は1から始まります)。これは不変のコレクションなので、フィルター/マップなどを呼び出すときに正しいタイプを返すようにしたいと思います。

ここここここのリソースを読みましたが、これを配列(または例にあるもの以外のコレクション)に変換する方法を理解するのに苦労しています。私はこの種の構造で正しい方向に進んでいますか?

class OneBasedArray[T] 
  extends Array[T] 
  with GenericTraversableTemplate[T, OneBasedArray]
  with ArrayLike[T, OneBasedArray]

コレクションの拡張を説明するのに役立つその他のリソースはありますか?

4

5 に答える 5

5

ちなみに、ArrayはScalaのコレクションではないと思います。

于 2010-12-07T22:27:33.867 に答える
3

AnArrayは a ではありませんTraversable-- それを基本クラスとして使用しようとすると、あらゆる種類の問題が発生します。また、不変ではないため、必要なものにはまったく適していません。最後にArray、実装です。特性または抽象クラスから継承してみてください。

于 2010-12-08T10:46:47.363 に答える
3

これは、操作対象のイテラブルの予想される実行時型を常に返すメソッドを使用して、イテラブルをポンピングする例です。

import scala.collection.generic.CanBuildFrom

trait MapOrElse[A] {
  val underlying: Iterable[A]

  def mapOrElse[B, To]
      (m: A => Unit)
      (pf: PartialFunction[A,B])
      (implicit cbf: CanBuildFrom[Iterable[A], B, To])
      : To = {

    var builder = cbf(underlying.repr)        

    for (a <- underlying) if (pf.isDefinedAt(a)) builder += pf(a) else m(a)

    builder.result
  }
}

implicit def toMapOrElse[A](it: Iterable[A]): MapOrElse[A] =
  new MapOrElse[A] {val underlying = it}

新しい関数mapOrElseは関数に似ていますが、未定義のときに呼び出される部分関数に加えてcollectメソッドを渡すことができます。たとえば、ロギング方法にすることができます。m: A => Unitpfpfm

于 2010-12-08T08:45:31.850 に答える
2

Array は、典型的な Scala コレクションではありません... これは、暗黙的な変換によってコレクションのように見せかけた単なる Java 配列です。

Java Array の混乱した分散を考えると、非常にやむを得ない理由がない限り Java Array を使用したくないでしょう。

(ここを参照してください: http://www.infoq.com/presentations/Java-Puzzlers )

シーケンスが 0 ベースであるという仮定に依存する他のコレクション メソッドの数を知る方法がないため、このような 1 ベースのコレクションをきしむことも実際には良い考えではありません。したがって、安全に行うには (本当に必要な場合)、デフォルトのメソッドを変更せずに新しいメソッドを追加する必要があります。

class OneBasedLookup[T](seq:Seq) {
  def atIdx(i:Int) = seq(i-1)
}

implicit def seqHasOneBasedLookup(seq:Seq) = new OneBasedLookup(seq)

// now use `atIdx` on any sequence.

さらに安全なことMap[Int,T]に、インデックスが 1 から始まる を作成できます。

(Iterator.from(1) zip seq).toMap

これはおそらく最も「正しい」ソリューションですが、パフォーマンス コストも最も高くなります。

于 2010-12-08T09:25:06.970 に答える
0

配列ではありませんが、最近まとめた 1 ベースの不変の IndexedSeq 実装を次に示します。RNA クラスを実装するhereの例に従いました。その例、ScalaDocs、および多くの「役立つ」コンパイラ エラーの間に、私はそれを正しくセットアップすることができました。OneBasedSeq が一般化されているという事実により、RNA の例よりも少し複雑になりました。また、この例で拡張されたトレイトとオーバーライドされたメソッドに加えて、メソッドを拡張IterableLikeしてオーバーライドする必要がありましたiterator。これは、さまざまなメソッドが裏でそのメソッドを呼び出しており、デフォルトの反復子がゼロベースであるためです。

文体的または慣用的な奇妙さをご容赦ください。Scala でプログラミングを始めて 2 か月未満です。

import collection.{IndexedSeqLike, IterableLike}
import collection.generic.CanBuildFrom
import collection.mutable.{Builder, ArrayBuffer}

// OneBasedSeq class
final class OneBasedSeq[T] private (s: Seq[T]) extends IndexedSeq[T]
  with IterableLike[T, OneBasedSeq[T]] with IndexedSeqLike[T, OneBasedSeq[T]]
{
  private val innerSeq = s.toIndexedSeq

  def apply(idx: Int): T = innerSeq(idx - 1)
  def length: Int = innerSeq.length
  override def iterator: Iterator[T] = new OneBasedSeqIterator(this)
  override def newBuilder: Builder[T, OneBasedSeq[T]] = OneBasedSeq.newBuilder
  override def toString = "OneBasedSeq" + super.toString
}

// OneBasedSeq companion object
object OneBasedSeq {
  private def fromSeq[T](s: Seq[T]) = new OneBasedSeq(s)

  def apply[T](vals: T*) = fromSeq(IndexedSeq(vals: _*))

  def newBuilder[T]: Builder[T, OneBasedSeq[T]] =
    new ArrayBuffer[T].mapResult(OneBasedSeq.fromSeq)

  implicit def canBuildFrom[T, U]: CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] =
    new CanBuildFrom[OneBasedSeq[T], U, OneBasedSeq[U]] {
      def apply() = newBuilder
      def apply(from: OneBasedSeq[T]): Builder[U, OneBasedSeq[U]] = newBuilder[U]
    }
}

// Iterator class for OneBasedSeq
class OneBasedSeqIterator[T](private val obs: OneBasedSeq[T]) extends Iterator[T]
{
  private var index = 1
  def hasNext: Boolean = index <= obs.length

  def next: T = {
    val ret = obs(index)
    index += 1
    ret
  }
}
于 2013-02-13T02:55:32.903 に答える