Last active
December 12, 2015 02:18
-
-
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…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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