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...