Today I had an interview about Scala and request was:
Implement a data structure with fixed size N , with these functionalities:
get(index)
set(index,value)
setall(value)
The complexity should be O(1)
example:
val ds = DS(100)
ds.set(4,5)
ds.get(4) //would return 5
ds.set(1,4)
ds.setall(10)
ds.get(4) //would return 10
ds.get(7) //would return 10
ds.set(1,7)
ds.get(1) //would return 7
Please find code that I have sent below.
My question would be Is this right solution and if there is a better way of doing it ?
import scala.collection.mutable.HashMap
trait Operations {
def get(index: Int): Int
def set(index: Int, value: Int)
def setall(value: Int)
}
class DS(N: Int) extends Operations {
var myMutableHashMap = new HashMap[Int, Int]().withDefaultValue(0)
def get(index: Int) = myMutableHashMap(index)
def set(index: Int, value: Int) = {
if (index <= N) myMutableHashMap += (index -> value)
}
def setall(value: Int) = {
myMutableHashMap = new HashMap[Int, Int]().withDefaultValue(value)
}
}
object Task {
def main(args: Array[String]): Unit = {
val ds = new DS(100)
ds.set(4, 5)
ds.get(4)
println(ds.get(4)) // -> 5
ds.setall(10)
println(ds.get(4)) //-> 10
println(ds.get(7)) //-> 10
ds.set(1, 7)
println(ds.get(1)) //-> 7
}
}
I am not sure if it is better, but I think HashMap might be a bit of an overkill.
The following solution might have a smaller footprint and takes less code.
Although, I would probably rather implement something more generic, it should fulfill the requirements you mentioned.
trait Operations {
def get(index: Int): Int
def set(index: Int, value: Int): Unit
def setall(fill: Int): Unit
}
class DS(size: Int) extends Operations {
val underlying: Array[Int] = new Array(size)
def get(index: Int): Int = underlying(index)
def set(index: Int, value: Int): Unit = underlying(index) = value
def setall(fill: Int): Unit = (0 until size).foreach(underlying(_) = fill)
}
Alternative, which just might give us a better 'setall' complexity but at a cost ...
trait Operations {
def get(index: Int): Int
def set(index: Int, value: Int): Unit
def setall(fill: Int): Unit
}
class DS(size: Int) extends Operations {
var underlying: Array[Integer] = new Array(size)
var default: Integer = new Integer(0)
def get(index: Int): Int = {
val result = underlying(index)
if (result == null) default else result
}
def set(index: Int, value: Int): Unit = underlying(index) = value
def setall(fill: Int): Unit = {
default = fill
underlying = new Array(size)
}
}
Related
In scala swing I can do something like the following:
val field = new TextField("", 4)
field.text = "Hello"
And the assignment is implemented thus:
def text_=(t: String): Unit = peer.setText(t)
But if I try my own implementation such as:
case class A(i: Int) {
def value_=(j: Int) = copy(i = j)
}
val a = A(3)
a.value = 3
This will not compile for me. What am I missing?
In Scala 2.13 (and 3) the setter def value_= (or def value_$eq) seems to work if you declare a field value
case class A(i: Int) {
val value: Int = 0
def value_=(j: Int) = copy(i = j)
}
or
case class A(i: Int, value: Int = 0) {
def value_=(j: Int) = copy(i = j)
}
By the way, it's a little confusing that a setter value_= returns A rather than Unit
println(a.value = 4) // A(4,0)
In Scala 2.12 the "setter" def value_= (or def value_$eq) works if you declare a "getter" too
case class A(i: Int) {
def value = "value"
def value_=(j: Int) = copy(i = j)
}
I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))
Is there a simple way to return a concrete type in an override method? And what about creating an instance of a concrete implementation? And calling chained methods implemented in the concrete class, so they return a correct type, too? I have a solution (based on https://stackoverflow.com/a/14905650) but I feel these things should be simpler.
There are many similar questions, but everyone's case is a little different, so here is another example (shortened from https://github.com/valdanylchuk/saiml/tree/master/src/main/scala/saiml/ga). When replying, if possible, please check if the whole code block compiles with your suggested change, because there are subtle cascading effects. I could not make this work with the "curiously recurring template pattern", for example (not that I find it nicer).
import scala.reflect.ClassTag
import scala.util.Random
abstract class Individual(val genome: String) {
type Self
def this() = this("") // please override with a random constructor
def crossover(that: Individual): Self
}
class HelloGenetic(override val genome: String) extends Individual {
type Self = HelloGenetic
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: Individual): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual {type Self = A} :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual {type Self = A} :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
The CRTP version is
abstract class Individual[A <: Individual[A]](val genome: String) {
def this() = this("") // please override with a random constructor
def crossover(that: A): A
}
class HelloGenetic(override val genome: String) extends Individual[HelloGenetic] {
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: HelloGenetic): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual[A] :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual[A] :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual[A] = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
which compiles. For creating the instances, I'd suggest just passing functions:
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, makeIndividual: () => A, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(makeIndividual())
...
}
If you want to pass them implicitly, you can easily do so:
trait IndividualFactory[A] {
def apply(): A
}
class HelloGenetic ... // remove def this()
object HelloGenetic {
implicit val factory: IndividualFactory[HelloGenetic] = new IndividualFactory[HelloGenetic] {
def apply() = new HelloGenetic(Random.alphanumeric.take("Hello, World!".length).mkString)
}
}
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None)
(implicit factory: IndividualFactory[A]) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(factory())
...
}
I have the following four methods, using BigDecimal to round a number:
private def round(input: Byte, scale: Int): Byte = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).byteValue()
}
private def round(input: Short, scale: Int): Short = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).shortValue()
}
private def round(input: Int, scale: Int): Int = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).intValue()
}
private def round(input: Long, scale: Int): Long = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).longValue()
}
And plan to generalize it into a single round:
private def round[T](input: Any, scale: Int, f: (BigDecimal) => T): T = {
f(BigDecimal(input.asInstanceOf[T]).setScale(scale, RoundingMode.HALF_UP))
}
and use this round like this:
round[Byte](b, scale, _.byteValue)
round[Short](s, scale, _.shortValue)
But the above generalized round didn't work because BigDecimal.apply cannot apply to T, what am I supposed to do?
You could use the Numeric type class
def round[T](input: T, scale: Int, f: BigDecimal => T)(implicit n: Numeric[T]): T = {
f(BigDecimal(n.toDouble(input)).setScale(scale, RoundingMode.HALF_UP))
}
Which can be used as:
round(5.525, 2, _.doubleValue)
res0: Double = 5.53
round(123456789L, -5, _.longValue)
res1: Long = 123500000
Another way might be to create a BigDecimalConverter type class, which is not as concise but solves the issue of converting to Double (which is not a good idea for a generic function, like Régis Jean-Gilles commented below).
Updated with a fromBigDecimal method to clean up the round function (thanks to Régis Jean-Gilles).
trait BigDecimalConverter[T] {
def toBigDecimal(in: T) : BigDecimal
def fromBigDecimal(bd: BigDecimal) : T
}
object BigDecimalConverter {
implicit object IntToBigDecimal extends BigDecimalConverter[Int] {
def toBigDecimal(in: Int) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toInt
}
implicit object DoubleToBigDecimal extends BigDecimalConverter[Double] {
def toBigDecimal(in: Double) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toDouble
}
implicit object LongToBigDecimal extends BigDecimalConverter[Long] {
def toBigDecimal(in: Long) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toLong
}
implicit object BigDecimalToBigDecimal extends BigDecimalConverter[BigDecimal] {
def toBigDecimal(in: BigDecimal) = in
def fromBigDecimal(bd: BigDecimal) = bd
}
}
def round[T](input: T, scale: Int)(implicit bdc: BigDecimalConverter[T]): T =
bdc.fromBigDecimal(
bdc.toBigDecimal(input).setScale(scale, BigDecimal.RoundingMode.HALF_UP)
)
Which can be correctly used with Double, Long, BigDecimal, ... :
round(10, 1)
round(Long.MaxValue - 1000L, -1)
round(BigDecimal("1234"), -2)
I'm trying to create a custom data type that behaves like an Int, but has certain specific behavior and typing (eg., it has to be positive, it has to fit within the range of our database's 'integer' type, etc).
To make it a friendly class, I want to have custom assignment operators, etc., for instance I'd like the following to all work:
val g: GPID = 1 // create a GPID type with value 1
val g: GPID = 1L // take assignment from a Long (and downcast into Int)
if (g == 1) ... // test the value of GPID type against an Int(1)
This is what I have so far but I'm not getting the expected behavior:
case class GPID(value: Int) extends MappedTo[Int] {
require(value >= 1, "GPID must be a positive number")
require(value <= GPDataTypes.integer._2, s"GPID upper bound is ${GPDataTypes.integer._2}")
def this(l: Long) = this(l.toInt)
def GPID = value
def GPID_=(i: Int) = new GPID(i)
def GPID_=(l: Long) = new GPID(l.toInt)
override def toString: String = value.toString
override def hashCode:Int = value
override def equals(that: Any): Boolean =
that match {
case that: Int => this.hashCode == that.hashCode
case that: Long => this.hashCode == that.hashCode
case _ => false
}
}
object GPID {
implicit val writesGPID = new Writes[GPID] {
def writes(g: GPID): JsValue = {
Json.obj(
"GPID" -> g.value
)
}
}
implicit val reads: Reads[GPID] = (
(__ \ "GPID").read[GPID]
)
def apply(l: Long) = new GPID(l.toInt)
implicit def gpid2int(g: GPID): Int = hashCode
implicit def gpid2long(g: GPID): Long = hashCode.toLong
}
The problems I have are:
Assignment doesn't work, for instance:
val g: GPID = 1
Implicit conversion is not working, for instance:
val i: Int = g
Any help would be appreciated... haven't build a custom type like this before so overriding assignment and implicit conversion is new to me...
object TestInt extends App {
class GPID(val value: Int) {
require(value >= 1, "GPID must be a positive number")
require(value <= 10, s"GPID upper bound is 10")
override def equals(that: Any) = value.equals(that)
override def toString = value.toString
// add more methods here (pimp my library)
}
implicit def fromInt(value: Int) = new GPID(value)
implicit def fromInt(value: Long) = new GPID(value.toInt) //possible loss of precision
val g: GPID = 1
val g2: GPID = 1L
if (g == 1)
println("ONE: " + g)
else
println("NOT ONE: " + g)
}
Prints:
ONE: 1