Expanding Scala Collections: An Unambiguous Array-Based Exercise

As an exercise, I would like to expand the Scala Array into my own OneBasedArray (does what you expect, indexing starts at 1). Since this is an immutable collection, I would like it to return the correct type when calling a filter / map, etc.

I read the resources here , here and here , but I'm trying to figure out how to translate this into arrays (or collections other than those shown in the examples). Am I on the right track with such a structure?

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

Are there any additional resources to help explain the expansion of the collections?

+6
scala scala-collections
source share
5 answers

The array is not a typical Scala collection ... It is simply a Java array that is compressed to look like a collection using implicit conversions.

Given the dispersed dispersion of Java arrays, you really don't want to use them without much reason, since they are a source of hidden errors.

(see here http://www.infoq.com/presentations/Java-Puzzlers )

Creating a 1-like collection like this is also not a good idea, since you have no way of knowing how many other collection methods rely on the assumption that sequences are based on 0. Therefore, to do this safely (if you really need to ), you need to add a new method, which by default remains unchanged:

 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. 

Even safer, you can create Map[Int,T] , with the indices being unidirectional

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

This is perhaps the most “right” solution, although it will also have the highest operating costs.

+2
source share
  • A detailed overview of the new collections API: Scala 2.8 collections API
  • To enjoy the relationship between the main classes and the features of this

By the way, I don't think Array is a collection in Scala.

+5
source share

The following is an example of scrambling iterations using a method that always returns the expected type of executable that it works with:

 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} 

The new mapOrElse function mapOrElse similar to the collect function, but it allows you to pass the m: A => Unit method in addition to the partial pf function, which is called whenever pf is undefined. m may be, for example, a protocol.

+3
source share

An Array not Traversable - trying to work with this as a base class will cause all kinds of problems. In addition, it is also not immutable, which makes it completely unsuitable for what you want. Finally, Array is an implementation - try to inherit from features or abstract classes.

+3
source share

Not an array, but a single, immutable IndexedSeq implementation that I recently compiled. I followed the example given here where they implement the RNA class. Between this example, ScalaDocs and a lot of “useful” compiler errors, I managed to configure it correctly. The fact that OneBasedSeq is generalized made it a little more complicated than the RNA example. In addition to the extended attributes and methods overridden in the example, I had to extend IterableLike and override the iterator method, because various methods call this method behind the scenes, and the default iterator is based on zero.

Please forgive any stylistic or idiomatic quirks; I have been programming in Scala for less than 2 months.

 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 } } 
0
source share

All Articles