General
Lazy evaluation
def expr = {
val xx = {println("x"); 1}
println("-after val x")
lazy val y = {println("y"); 2}
println("-after lazy val y")
def z = {println("z"); 3}
println("-after def z")
xx + y + z + xx + y + z
}
expr
This will print:
x
-after val x
-after lazy val y
-after def z
y
z
z
res6: Int = 12
To sum up: val xx
will be evaluated immediately, lazy val y
will be evaluated only once in addition to be evaluated during first call; def z
expression will be evaluated every time it's called.
flatMap tricky behaviour with Maps
scala> val d = Map("a" -> List(1,2,3), "b" -> List(3,4,5), "c" -> List(6,7,8, 10))
d: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(1, 2, 3), b -> List(3, 4, 5), c -> List(6, 7, 8, 10))
scala> d
res2: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(1, 2, 3), b -> List(3, 4, 5), c -> List(6, 7, 8, 10))
scala> d.flatMap(x => x._2.map(i => x._1 -> i)).toList
res3: List[(String, Int)] = List((a,3), (b,5), (c,10))
scala> d.toList.flatMap(x => x._2.map(i => x._1 -> i)).toList
res4: List[(String, Int)] = List((a,1), (a,2), (a,3), (b,3), (b,4), (b,5), (c,6), (c,7), (c,8), (c,10))
JSON
For handling JSON, this is the best library I've found (so far): https://circe.github.io/
build.sbt
:
val circeVersion = "0.10.0"
libraryDependencies ++= Seq(
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion,
)
Parsing
import io.circe.parser._
parse(message) match {
case Right(json) => "do sth here"
case Left(fail) => ":("
}
Parse to custom case class
Input is JSON lines, looking like this:
["asd",{"mean":1.1134670192002851,"max":29.0,"stdDev":1.6615975596464523,"min":0.0}]
["fdsa",{"mean":0.82914166017361,"max":69.0,"min":0.0}]
DTOs:
import io.circe.generic.JsonCodec
@JsonCodec case class ScalerMetadataValues(min: Option[Double], max: Option[Double],
mean: Option[Double], stdDev: Option[Double])
case class ScalerMetadata(columnName: String, metadata: ScalerMetadataValues)
Decoder (can also be implicit
)
import io.circe.{Decoder, HCursor}
object ScalerMetadataJson {
val decoder: Decoder[ScalerMetadata] = (cursor: HCursor) => {
for {
name <- cursor.downN(0).as[String]
metadata <- cursor.downN(1).as[ScalerMetadataValues]
} yield ScalerMetadata(name, metadata)
}
}
Usage:
import io.circe.parser.decode
decode[ScalerMetadata](str)(ScalerMetadataJson.decoder) match {
case Left(_) => throw new Exception(s"Invalid JSON in metadata: `$str`")
case Right(value) => value
}
Pattern matching
Pattern matching on generic type [T]
import scala.collection.JavaConverters._
import scala.reflect.runtime.universe._
protected def getValuesFromRequest[T: TypeTag](request: SeldonMessage, columnIdx: Int): Option[List[T]] = {
val values: List[T] = request.getData.getNdarray.getValuesList
.iterator().asScala
.map(v => {
val valuesRaw = v.getListValue.getValues(columnIdx)
typeOf[T] match {
case t if t =:= typeOf[Double] => Some(valuesRaw.getNumberValue)
case t if t =:= typeOf[String] => Some(valuesRaw.getStringValue)
case _ => None
}
})
.filter(x => x.isDefined)
.map(_.get.asInstanceOf[T])
.toList
if(values.isEmpty) None else Some(values)
}
Other
Random Long with constraints
Use Apache Commons Math
:
// .sbt
libraryDependencies += "org.apache.commons" % "commons-math3" % "3.6.1"
Usage:
import org.apache.commons.math3.random.RandomDataGenerator
new RandomDataGenerator().nextLong(0, 666)
Measure execution time of a code block
i.e in REPL for quick testing
def time[R](block: => R): R = {
val t0 = System.nanoTime()
val result = block // call-by-name
val t1 = System.nanoTime()
println("Elapsed time: " + (t1 - t0)/1000000.0 + "ms")
result
}
//Usage:
var list = time {List.range(1,1000, 1)}
No matches...