Skip to content

Instantly share code, notes, and snippets.

@fcroiseaux
Last active December 12, 2015 02:18
Show Gist options
  • Save fcroiseaux/4697420 to your computer and use it in GitHub Desktop.
Save fcroiseaux/4697420 to your computer and use it in GitHub Desktop.
Une solution à l'exercice Jajascript du concours Code Story 2013 en Play/Scala avec utilisation des Iteratee pour le chargement des 50000 vols "à la volée". Cette solution donne 10000 points. L'ensemble des vols est chargé au fur et à mesure du parsing de la requête http et les vols sont stockées dans un ensemble trié par ordre inverse des heure…
package controllers
import play.api._
import libs.iteratee.Iteratee
import libs.json.{JsValue, JsArray, Json}
import play.api.mvc._
import models._
import collection.mutable
object Application extends Controller {
def removeLast(s: String, c: Char) = s.take(s.lastIndexOf(c))
val inverseOrderByStart = Ordering[(Int, String)].on[Flight](o => (-o.start, o.name))
def fromJson(js: JsValue) = Flight(
(js \ "VOL").as[String],
(js \ "DEPART").as[Int],
(js \ "DUREE").as[Int],
(js \ "PRIX").as[Int]
)
def flightIteratee(s: mutable.SortedSet[Flight]): Iteratee[Array[Byte], (String, mutable.SortedSet[Flight])] = {
Iteratee.fold[Array[Byte], (String, mutable.SortedSet[Flight])](("", s)) {
(lastChunk, bytes) =>
// Retrieve the part that has not been processed in the previous chunk and copy it in front of the current chunk
val content = lastChunk._1 + new String(bytes)
val chunckBody = content.drop(content.indexOf('[') + 1)
val jsonObjs = if (chunckBody.contains(']')) // This is the last chunk
"[" + chunckBody
else
"[" + removeLast(removeLast(chunckBody, '{'), ',') + "]"
val orders: List[Flight] = Json.parse(jsonObjs) match {
case l: JsArray => l.value.map(v => fromJson(v)).toList
case _ => List()
}
// Add all flights to the sorted TreeSet
orders.foreach(lastChunk._2.add(_))
// Put forward the part that has not been processed
val last = chunckBody.takeRight(chunckBody.size - chunckBody.lastIndexOf('{'))
(last, lastChunk._2)
}
}
def requestIteratee(s: mutable.SortedSet[Flight]) = BodyParser(rh => flightIteratee(s).map(Right(_)))
// progressively parse the big flight json file.
def optimize = Action(requestIteratee(mutable.SortedSet[Flight]()(inverseOrderByStart))) {
rq: Request[(String, mutable.SortedSet[Flight])] =>
val orders = rq.body._2
val (path, price) = Jajascript.optimize(orders)
val result = Json.obj(
"gain" -> price,
"path" -> path
)
Ok(result)
}
}
package models
import collection.mutable
case class Flight(name: String, start: Int, length: Int, price: Int) {
lazy val end = start + length
}
object Jajascript {
case class Mission(price: Int, order: Flight, path: List[String])
val orderByPrice = Ordering[(Int, String)].on[Mission](m => (-m.price, m.order.name))
def optimize(orders: mutable.SortedSet[Flight]) = {
val missions = mutable.SortedSet[Mission]()(orderByPrice)
orders.foreach {
o =>
val miss = missions.view find {
m => o.end <= m.order.start
}
missions add (miss match {
case None => Mission(o.price, o, List(o.name))
case Some(best) => Mission(o.price + best.price, o, o.name :: best.path)
})
}
val max = missions.head
(max.path, max.price)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment