Scala: List[Tuple3] to Map[String,String] - list

I've got a query result of List[(Int,String,Double)] that I need to convert to a Map[String,String] (for display in an html select list)
My hacked solution is:
val prices = (dao.getPricing flatMap {
case(id, label, fee) =>
Map(id.toString -> (label+" $"+fee))
}).toMap
there must be a better way to achieve the same...

How about this?
val prices: Map[String, String] =
dao.getPricing.map {
case (id, label, fee) => (id.toString -> (label + " $" + fee))
}(collection.breakOut)
The method collection.breakOut provides a CanBuildFrom instance that ensures that even if you're mapping from a List, a Map is reconstructed, thanks to the type annotation, and avoids the creation of an intermediary collection.

A little more concise:
val prices =
dao.getPricing.map { case (id, label, fee) => ( id.toString, label+" $"+fee)} toMap
shorter alternative:
val prices =
dao.getPricing.map { p => ( p._1.toString, p._2+" $"+p._3)} toMap

Related

Clickable list different intents Kotlin

I'm retrieving data to list and I need to make 2 different intents. "Activities" needs to start "e" intent and rest starts "i" intent.
binding.listview.adapter = MyAdapter(this, personArrayList)
binding.listview.isClickable = true
binding.listview.setOnItemClickListener{
parent, view, position, id ->
val name = name[position]
val activities = activities[position]
val activityTime = activityTime[position]
val description = description[position]
val imageID = imageID[position]
val i = Intent(this, DescriptionActivity::class.java)
val e = Intent(this, ProfileScreen::class.java)
i.putExtra("name", name)
i.putExtra("activityTime", activityTime)
e.putExtra("activities",activities)
i.putExtra("imageID", imageID)
i.putExtra("description", description)
startActivity(i)
}
Maybe second list is an option, but im looking to make this work in one list for now.

In Scala what is the most efficient way to remove elements in a list based on being similar to another element?

I have a long list of objects around 300, with each object in the list having this data structure:
case class MyObject(id: String,
name: String,
colour: String,
price: Int
height: Int
width: Int,
desc: String)
I can’t work out what is the best way to go through the list and for each object remove any other object that has the same name, colour, price, height and width. Note that this isn’t a simple dedupe as the ids and desc can be different. The input and output need to remain List[MyObject] and I do not know beforehand which objects are the duplicated ones.
This is my initial solution which works, but not sure its the most efficient way of doing it when it comes to dealing with large list.
def removeDuplicates(originalList: List[MyObject]): List[MyObject] = {
def loop(remaining: List[MyObject], acc: List[MyObject]): List[MyObject] = {
remaining match {
case head :: tail =>
val listOfDuplicates = tail.filter{ x =>
x.name == head.name &&
x.colour == head.colour &&
x.price == head.price &&
x.height == head.height &&
x.width == head.width
}
val deDupedTail = tail.filter(!listOfDuplicates.contains(_))
loop(deDupedTail, acc ::: listOfDuplicates)
case Nil => acc
}
}
val listOfDuplicateObjects = loop(originalList, List())
originalList.filter(!listOfDuplicateObjects.contains(_))
}
Not sure if it's most efficent, but IMHO it's elegant:
originalList.distinctBy(o => (o.name, o.colour, o.price, o.height, o.width))

How to remove double quotes from keys in RDD and split JSON into two lines?

I need to modify the data to give input to CEP system, my current data looks like below
val rdd = {"var":"system-ready","value":0.0,"objectID":"2018","partnumber":2,"t":"2017-08-25 11:27:39.000"}
I need output like
t = "2017-08-25 11:27:39.000
Check = { var = "system-ready",value = 0.0, objectID = "2018", partnumber = 2 }
I have to write RDD map operations to achieve this if anybody suggests better option welcome. colcount is the number of columns.
rdd.map(x => x.split("\":").mkString("\" ="))
.map((f => (f.dropRight(1).split(",").last.toString, f.drop(1).split(",").toSeq.take(colCount-1).toString)))
.map(f => (f._1, f._2.replace("WrappedArray(", "Check = {")))
.map(f => (f._1.drop(0).replace("\"t\"", "t"), f._2.dropRight(1).replace("(", "{"))) /
.map(f => f.toString().split(",C").mkString("\nC").replace(")", "}").drop(0).replace("(", "")) // replacing , with \n, droping (
.map(f => f.replace("\" =\"", "=\"").replace("\", \"", "\",").replace("\" =", "=").replace(", \"", ",").replace("{\"", "{"))
Scala's JSON parser seems to be a good choice for this problem:
import scala.util.parsing.json
rdd.map( x => {
JSON.parseFull(x).get.asInstanceOf[Map[String,String]]
})
This will result in an RDD[Map[String, String]]. You can then access the t field from the JSON, for example, using:
.map(dict => "t = "+dict("t"))

Size check on future list in Scala

I have a method which return Future[List[Employee]]. I want to check the list size for various purpose. I am not able to call size on list and I think its because its in Future. Any suggestion?
val employees: Future[List[Employee]] = companyService.findEmployeesWorkingOn(someDate)
employees match {
case emp if(emp.size == 1) => Logger.info("Only one employee working")
case emp if(emp.size == 0) => Logger.info("No one working")
case _ => Logger.info("Multiple employees working")
}
You need to "wait" for the future to happen or not. You can use map to map the Future[List[Employee]] to a Future[Int] and use the onSuccess callback.
val sizeFuture = employees.map(_.size) // returns a Future[Int]
sizeFuture onSuccess {
case size:Int => println(size) // do your stuff here
}
Use a for comprehension which desugars to a flatMap,
for ( e <- employees ) yield e.size match {...}
Here list e is matched only if the future succeeds.
No need to check the size for your use case:
val employees: Future[List[Employee]] = …
val result = employees map {
case Nil => "no employees"
case List(e) => "one employee"
case es => "multiple employees"
}

slick 3 two leftJoin query result to classes mapping

Current question is relative with next one, but now I need to read the data from database instead of insert.
I have next three case classes:
case class A (id: Long, bList: List[B])
case class B (id: Long, aId: cList: List[C])
case class C (id: Long, bId: Long)
And query with two leftJoin functions and incomingAId for filtering aTable results:
val query = (for {
((aResult,bResult),cResult) <- aTable.filter(_.id === incomigAId)
.joinLeft(bTable).on(_.id === _.aId)
.joinLeft(cTable).on(_._2.map(_.id) === _.bId)
} yield ((aResult,bResult),cResult)).result.transactionally
Next query works and the result looks valid, but isn't easy to handle it to the case classes. Also, executionResult has Seq[Nothing] type and process of mapping requires something like that:
database.run(query).map{ executionResult =>
executionResult.map { vectorElement: [Tuple2[Tuple2[A, Option[B]], Option[C]]]
...
}
}
Is there any proper way to prevent Seq[Nothing] (changes in query)?
Or if the query result type is fine, could you please share solution how to map it to the case classes above?
Right now I'm using next solution, but I suppose that some part of code can be optimized (e.g. groupBy replacing with something else).
execute(query).mapTo[Vector[((A, Option[B]), Option[C])]]
.flatMap { insideFuture =>
insideFuture.groupBy(_._1._1).mapValues { values =>
//scala groupBy losts ordering
val orderedB = values.groupBy(_._1._2).toSeq.sortBy(_._1.map(_.id)).toMap
orderedB.mapValues(_.map(_._2))
}.headOption match {
case Some(data) => Future.successful {
data._1.copy(bList = data._2.map {
case (Some(bElement), optionCElements) =>
bElement.copy(cList = optionCElements.toList.flatten)
case _ =>
throw new Exception("Invalid query result. Unable to find B elements")
}.toList)
}
case None => Future.failed(new Exception("Unable to find A with next id " + incomigAId))
}
}
}