Skip to content

Instantly share code, notes, and snippets.

@mosser
Last active January 7, 2018 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mosser/3fd0a274af3e001bba9d2b1d5d15a26c to your computer and use it in GitHub Desktop.
Save mosser/3fd0a274af3e001bba9d2b1d5d15a26c to your computer and use it in GitHub Desktop.
Merging maps
import scala.util.Random
// Context
case class Event(data: Map[String, Int])
// Generate a random history of given size
def history(size: Int): Seq[Event] = {
for (i <- 1 to size)
yield Event((1 to Random.nextInt(10) map {
_ => Random.nextInt(10).toString -> Random.nextInt(100)
}).toMap)
}
// alternative #1
def alt1(history: Seq[Event]): Map[String,Int]= {
val keys = history.flatMap(_.data.keySet).distinct
val tmp = keys.map { k => k -> history.flatMap(_.data.get(k)).sum }
tmp.toMap
}
// alternative #2
def alt2(history: Seq[Event]): Map[String,Int] =
(Map[String, Int]() /: history) { (acc, elem) =>
acc ++ elem.data.map { case (k, v) => k -> (acc.getOrElse(k, 0) + v) }
}
// Benchmark
def timer[T,U](setup: => T)(first: T => U, second: T => U): (U, Long, Long) = {
val ctx = setup
val t1S = System.nanoTime()
val r1 = first(ctx)
val t1E = System.nanoTime()
val r2 = second(ctx)
val t2E = System.nanoTime()
assert(r1 == r2)
(r1, t1E-t1S, t2E-t1E)
}
def benchmark(howMany: Int): Map[String, Double] = {
val times: Seq[(Long,Long)] = 1 to howMany map { _ =>
val (_, t1, t2) = timer(history(10000))(h => alt1(h), h => alt2(h))
(t1,t2)
}
Map(
"alt1" -> times.map {_._1}.sum / times.length ,
"alt2" -> times.map {_._2}.sum / times.length
)
}
benchmark(100)
// inverting alt1 and alt2 in the bench, avoiding JVM side effects
def benchmark2(howMany: Int): Map[String, Double] = {
val times: Seq[(Long,Long)] = 1 to howMany map { _ =>
val (_, t2, t1) = timer(history(10000))(h => alt2(h), h => alt1(h))
(t1,t2)
}
Map(
"alt1" -> times.map {_._1}.sum / times.length ,
"alt2" -> times.map {_._2}.sum / times.length
)
}
benchmark2(100)
import scala.util.Random
defined class Event
history: history[](val size: Int) => Seq[Event]
alt1: alt1[](val history: Seq[Event]) => Map[String,Int]
alt2: alt2[](val history: Seq[Event]) => Map[String,Int]
timer: timer[T,U](val setup: => T)(val first: T => U,val second: T => U) => (U, Long, Long)
benchmark: benchmark[](val howMany: Int) => Map[String,Double]
res0: Map[String,Double] = Map(alt1 -> 3.7475511E7, alt2 -> 1.4487694E7)
res1: Map[String,Double] = Map(alt1 -> 3.7172239E7, alt2 -> 1.2503222E7)
@scand1sk
Copy link

scand1sk commented Jan 7, 2018

Pour générer les données tu as les méthodes Seq.fill qui sont bien pratiques :)
E.g.

def history(size: Int): Seq[Event] = {
  Seq.fill(size) {
    Event(Seq.fill(Random.nextInt(10))(
        Random.nextInt(10).toString -> Random.nextInt(100)
    ).toMap)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment