Scala kogumi implementeerimine
Selles praktikumis loome uue järjekorra kogumi.
Implementeerime selle kahe listi (xs
ja ys
) abil.
Alustame andmestruktuuri konktreetsete meetodite implementeerimisest ja siis lisame selle Scala kogumite klassihierarhiasse.
Implementeerime andmestruktuuri põhioperatsioonid.
import scala.language.higherKinds trait J2rjekordOps[+T,CC[_]] { def onTyhi: Boolean def lisaAlgusse[Q >: T](x:Q):CC[Q] def v6taL6pust[Q >: T]:(Q, CC[Q]) } case class J2rjekord[+T] (protected val xs: List[T], protected val ys: List[T]) extends J2rjekordOps[T,J2rjekord] { override def toString = s"J2rjekord($xs, $ys)" override def onTyhi: Boolean = ??? override def lisaAlgusse[Q >: T](x: Q): J2rjekord[Q] = ??? override def v6taL6pust[Q >: T]: (Q, J2rjekord[Q]) = ??? } object TestJ2rjekord1 { def main(args: Array[String]): Unit = { val a = J2rjekord[Int](List(),List()) assert(a.onTyhi) assert(!a.lisaAlgusse(1).onTyhi) assert(a.lisaAlgusse(1) == J2rjekord(List(1), List())) assert(a.lisaAlgusse(2) == J2rjekord(List(2), List())) val b = J2rjekord(List(6,5,4),List(1,2,3)) assert(b.lisaAlgusse(7) == J2rjekord(List(7,6,5,4), List(1,2,3))) val (x,c) = b.v6taL6pust assert(x == 1) assert(c == J2rjekord(List(6,5,4),List(2,3))) assert(c.v6taL6pust == (2, J2rjekord(List(6,5,4),List(3)))) assert(a.lisaAlgusse(7).v6taL6pust == (7, J2rjekord(List(),List()))) } }
Kogumi loomine kompanjonobjektiga
Kogumi loomisel lisame elemendid järjekorraga vasakult paremale. S.t.
J2rjekord(1,2) == J2rjekord().lisaAlgusse(1).lisaAlgusse(2)
object J2rjekord { def apply[T](xs: T*): J2rjekord[T] = ??? } object TestJ2rjekord2 { def main(args: Array[String]): Unit = { val a = J2rjekord[Int](List(),List()) val b = J2rjekord(List(6,5,4,3,2,1), List()) assert(a == J2rjekord()) assert(b == J2rjekord(1,2,3,4,5,6)) } }
Scala kogumina (osa 1)
Esmalt lisame kolm asja: pikkuse arvutamise, indekseerimise ja kogumile vastava kompanjonobjekti. Viimane tähendab vastavat tüüpi builderi lisamine kompanjonobjekti. (apply
meetod genereeritakse nüüd automaatselt builderi abil.)
case class J2rjekord[+T] (protected val xs: List[T], protected val ys: List[T]) extends AbstractSeq[T] with LinearSeq[T] with GenericTraversableTemplate[T, J2rjekord] with J2rjekordOps[T,J2rjekord] { // meetodid eelmisest koodilõigust override def companion: GenericCompanion[J2rjekord] = J2rjekord override val length: Int = ??? override def apply(idx: Int): T = ??? } object J2rjekord extends GenericCompanion[J2rjekord] { class MyCBF[A, Coll] extends CanBuildFrom[Coll, A, J2rjekord[A]] { override def apply(from: Coll): mutable.Builder[A, J2rjekord[A]] = newBuilder override def apply(): mutable.Builder[A, J2rjekord[A]] = newBuilder } implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, J2rjekord[A]] = new MyCBF[A,Coll] override def newBuilder[A]: mutable.Builder[A, J2rjekord[A]] = new mutable.Builder[A, J2rjekord[A]] { private var list = List[A]() // kasutage seda muutujat ehitamiseks override def +=(elem: A): this.type = ??? override def clear(): Unit = ??? override def result(): J2rjekord[A] = ??? } } object TestJ2rjekord3 { def main(args: Array[String]): Unit = { val a = J2rjekord(6,7,8,9) // testimiseks kasutame toString-i kuna equals defineerime hiljem assert(a.toString == J2rjekord(List(9,8,7,6),List()).toString) val b = J2rjekord(List(6,5,4),List(1,2,3)) assert(b.length == 6) assert(b(0) == 1) assert(b(1) == 2) assert(b(2) == 3) assert(b(3) == 4) assert(b(4) == 5) assert(b(5) == 6) } }
J2rjekord
Scala kogumina (osa 2)
Nüüd lisage iteraator. Võrduse kontrolli kood on etteantud.
case class J2rjekord[+T] (protected val xs: List[T], protected val ys: List[T]) extends AbstractSeq[T] with LinearSeq[T] with GenericTraversableTemplate[T, J2rjekord] with LinearSeqLike[T, J2rjekord[T]] with Equals with J2rjekordOps[T,J2rjekord] { // meetodid eelmisest koodilõigust override def iterator: Iterator[T] = new Iterator[T] { private var cons = xs private var snoc = ys private var l = xs.length + ys.length // järgnevad meetodid peavad kasutama (ja muutma) eelnevaid muutujaid override def hasNext: Boolean = ??? override def next(): T = ??? } override def canEqual(other: Any): Boolean = other.isInstanceOf[J2rjekord[_]] override def equals(other: Any): Boolean = other match { case that: J2rjekord[_] => super.equals(that) && (that canEqual this) && (this, that).zipped.forall(_ == _) case _ => false } override def hashCode(): Int = { this.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } } object TestJ2rjekord4 { def main(args: Array[String]): Unit = { val a = J2rjekord(6,7,8,9) // prindib "6 7 8 9" for (x <- a) print(s"$x ") println() assert(a == J2rjekord(List(9,8,7,6),List())) assert(a == J2rjekord(List(),List(6,7,8,9))) assert(a.map(10+_) == J2rjekord(16,17,18,19)) } }
Optimeeritud implementatsioonid
Tänu iteraatori lisamisele on meil nüüd kasutatav suur hulk meetode, näiteks map
, :+
ja +:
. Nende vaikeimplementatsioon pole aga järjekorrale omane. Näiteks, algusse lisamine peaks olema konstantse ajaga tehtav aga vaikeimplementatsioon on lineaarne.
Katke järgnevad meetodid üle sobilikuma implementatsiooniga. (CanBuildFrom
-i argumendina võtvad funktsioonid lahendage samamoodi nagu map
.)
case class J2rjekord[+T] (protected val xs: List[T], protected val ys: List[T]) extends AbstractSeq[T] with LinearSeq[T] with GenericTraversableTemplate[T, J2rjekord] with LinearSeqLike[T, J2rjekord[T]] with Equals with J2rjekordOps[T,J2rjekord] { // meetodid eelmisest koodilõigust override def head: T = ??? override def tail: J2rjekord[T] = ??? override def forall(p: T => Boolean): Boolean = ??? override def exists(p: T => Boolean): Boolean = ??? override def +:[B >: T, That](elem: B) (implicit bf: CanBuildFrom[J2rjekord[T], B, That]): That = ??? override def :+[B >: T, That](elem: B) (implicit bf: CanBuildFrom[J2rjekord[T], B, That]): That = ??? override def reverse: J2rjekord[T] = ??? // sama mustriga teha +:, :+ override def map[B, That](f: T => B) (implicit bf: CanBuildFrom[J2rjekord[T], B, That]): That = bf match { case _: J2rjekord.MyCBF[_, _] => new J2rjekord(xs.map(f), ys.map(f)).asInstanceOf[That] case _ => super.map(f)(bf) } } object TestJ2rjekord5 { def main(args: Array[String]): Unit = { val a = J2rjekord(6,7,8,9) assert(a.head == 6) assert(a.tail == J2rjekord(7,8,9)) assert(a.tail.tail == J2rjekord(8,9)) assert(a.forall(_ < 10)) assert(!a.forall(_ < 7)) assert(a.exists(_ == 7)) assert(!a.exists(_ == 5)) assert(5 +: a == J2rjekord(5,6,7,8,9)) assert(a :+ 10 == J2rjekord(6,7,8,9,10)) assert(a.map(10+_) == J2rjekord(16,17,18,19)) } }