How to convert Future[Seq[A]] into Map[String, Seq[A]]? - scala

I have a function which return a Future[Seq[A]]
def foo(x:String): Future[Seq[A]]
Then how can I convert it into a Map[String, Seq[A]] ?
This is What I have tried
foo(x).map { e =>
(ResponseHeader.Ok, e.groupBy(_.use).mapValues(???))
}
*EDIT :
What I want to achieve is to group by my Seq based on 1 of its column as the key, and convert it into a Map[key, Seq[A]].
I tried to group by it, but I dont know what to put inside the mapValues

The mapValues call is not required, the groupBy will give you what you want:
val e: Seq[A] = ???
val map: Map[String, Seq[A]] = e.groupBy(_.use)
val res: Future[(Int, Map[String, Seq[A]])] =
foo("").map { e =>
(ResponseHeader.Ok, e.groupBy(_.use))
}

Related

No implicits found for parameter ev: Any <:< (T_, U_)

I'm trying to create a map based on conditions. Here's the general workflow in pseudocode:
def createMyMap(input: String): Map[String, String] = {
val stringArray = input.split(",")
stringArray.map(element => {
if (condition) {
newKey -> newVal
}
}).toMap
}
and I see two compile errors:
No implicits found for parameter ev: Any <:< (T_, U_) in the toMap call
For the method createMyMap
Type mismatch.
Required: scala.Predef.Map [String, String]
Found: scala.collection.immutable.Map[Nothing, Nothing]
This makes sense since the compiler doesn't know how to create the map if the condition isn't fulfilled. For example, if I add this in the method:
if (condition) {
newKey -> new Val
} else {
null
}
then it'll compile. I'm just not too sure how to approach the else - how do I avoid this kind of problem? I'm running into this because I only want to create a map entry if a condition is fulfilled.
It's not clear how newKey and newVal are derived, but here is the template code using collect
def createMyMap(input: String): Map[String, String] =
input.split(",").collect {
case s if <condition> =>
newKey -> newVal
}.to(Map)
e.g.
def createMyMap(input: String): Map[String, String] =
input.split(",").collect {
case s if s.contains('.') =>
s -> "data"
}.to(Map)
You have a few good options that I'll summarize from the comments:
filter + map + toMap
// stringArray: Traversable[String]
// condition: String => Boolean
// transform: String => (String, String)
val result: Map[String, String] = stringArray
.filter(condition)
.map(transform)
.toMap
map + flatten + toMap
val result: Map[String, String] = stringArray
.map { k =>
if (condition(k)) Some(transform(k))
else None
}
.flatten
.toMap
flatMap + toMap
val result: Map[String, String] = stringArray
.flatMap { k =>
if (condition(k)) Some(transform(k))
else None
}
.toMap
collect + toMap
val result: Map[String, String] = stringArray
.collect {
case k if condition(s) => transform(k)
}
.toMap
See documentation.
In short, methods 3 and 4 are especially clean (although all are good IMO). However, the one that is semantically the most readable IMO is 4, which uses collect (with option 1 being a close second).

Extracting Object from Some() and Using it

In the below code, encoded is a JSON string. The JSON.parseFull() function is returning an object of the form: Some(Map(...)). I am using .get to extract the Map, but am unable to index it as the compiler sees it as type Any. Is there any to provide the compiler visibility that it is, in fact, a map?
val parsed = JSON.parseFull(encoded)
val mapped = parsed.get
You can utilize the collect with pattern matching to match on the type:
scala> val parsed: Option[Any] = Some(Map("1" -> List("1")))
parsed: Option[Any] = Some(Map(1 -> List(1)))
scala> val mapped = parsed.collect{
case map: Map[String, Any] => map
}
mapped: Option[Map[String,Any]] = Some(Map(1 -> List(1)))
You can do something like the following in the case of a List value to get values from the List:
scala> mapped.get.map{ case(k, List(item1)) => item1}
res0: scala.collection.immutable.Iterable[Any] = List(1)
I was able to use a combination of the get function and pattern matching similar to what was posted in Tanjin's response to get the desired result.
object ReadFHIR {
def fatal(msg: String) = throw new Exception(msg)
def main (args: Array[String]): Unit = {
val fc = new FhirContext()
val client = fc.newRestfulGenericClient("http://test.fhir.org/r2")
val bundle = client.search().forResource("Observation")
.prettyPrint()
.execute()
val jsonParser = fc.newJsonParser()
val encoded = jsonParser.encodeBundleToString(bundle)
val parsed = JSON.parseFull(encoded)
val mapped: Map[String, Any] = parsed.get match{
case map: Map[String, Any] => map
}
println(mapped("resourceType"))
}
}

How to convert mutable.Map to mutable.HashMap in Scala?

I'm extending Sparks AccumulableParam[mutable.HashMap[Int,Long], Int] with Scala, for some experiments. Part of this, is to define the method def addInPlace(t1: mutable.HashMap[Int,Long], t2: mutable.HashMap[Int,Long]): mutable.HashMap[Int,Long].
What I want to do:
import scala.collection.mutable.HashMap
def addInPlace(t1: mutable.HashMap[Int,Long], t2: mutable.HashMap[Int,Long]):
mutable.HashMap[Int,Long] = {
t1 ++ t2.map { case (s, c) => (s, c + t1.getOrElse(s, 0L)) }
}
I get the error:
Expression of type mutable.Map[Int, Long] doesn't conform to selected type mutable.HashMap[Int, Long]
In this case the ++ operator returns Map instead of HashMap, even though both terms t1 and t2.map {...} are of type HashMap[int, Long].
So my question is, how to make ++ return a HashMap instead, or how to convert the resulting Map to a HashMap.
An ugly way to do it is to use asInstanceOf[mutable.HashMap[Int, Long]] on the result map:
def addInPlace(t1: mutable.HashMap[Int,Long], t2: mutable.HashMap[Int,Long]): mutable.HashMap[Int,Long] = {
val result = t1 ++ t2.map { case (s, c) => (s, c + t1.getOrElse(s, 0L)) }
result.asInstanceOf[mutable.HashMap[Int, Long]]
}

How to flatten a sequence of cats' ValidatedNel values

I need to flatten a sequence of cats.data.ValidatedNel[E, T] values to a single ValidatedNel value:
val results: Seq[cats.data.ValidatedNel[E, T]] = ???
val flattenedResult: cats.data.ValidatedNel[E, T]
I can do it like this:
import cats.std.list._, cats.syntax.cartesian._
results.reduce(_ |#| _ map { case _ => validatedValue })
but wonder if a pre-defined library methods exists.
It depends on how you want to combine them (what is validatedValue in your question ?)
import cats.data.{Validated, ValidatedNel}
import cats.implicits._
val validations1 = List(1.validNel[String], 2.valid, 3.valid)
val validations2 = List(1.validNel[String], "kaboom".invalidNel, "boom".invalidNel)
If you want to combine the Ts, you can use Foldable.combineAll which uses a Monoid[T] :
val valSum1 = validations1.combineAll
// Valid(6)
val valSum2 = validations2.combineAll
// Invalid(OneAnd(kaboom,List(boom)))
If you want to get a ValidationNel[String, List[T]], you can use Traverse.sequence :
val valList1: ValidatedNel[String, List[Int]] = validations1.sequence
// Valid(List(1, 2, 3))
val valList2: ValidatedNel[String, List[Int]] = validations2.sequence
// Invalid(OneAnd(kaboom,List(boom)))
If you don't care about the result, which seems to be the case, you can use Foldable.sequence_.
val result1: ValidatedNel[String, Unit] = validations1.sequence_
// Valid(())
val result2: ValidatedNel[String, Unit] = validations2.sequence_
// Invalid(OneAnd(kaboom,List(boom)))
validations1.sequence_.as(validatedValue) // as(x) is equal to map(_ => x)

applying partial function on a tuple field, maintaining the tuple structure

I have a PartialFunction[String,String] and a Map[String,String].
I want to apply the partial functions on the map values and collect the entries for which it was applicaple.
i.e. given:
val m = Map( "a"->"1", "b"->"2" )
val pf : PartialFunction[String,String] = {
case "1" => "11"
}
I'd like to somehow combine _._2 with pfand be able to do this:
val composedPf : PartialFunction[(String,String),(String,String)] = /*someMagicalOperator(_._2,pf)*/
val collected : Map[String,String] = m.collect( composedPf )
// collected should be Map( "a"->"11" )
so far the best I got was this:
val composedPf = new PartialFunction[(String,String),(String,String)]{
override def isDefinedAt(x: (String, String)): Boolean = pf.isDefinedAt(x._2)
override def apply(v1: (String, String)): (String,String) = v1._1 -> pf(v1._2)
}
is there a better way?
Here is the magical operator:
val composedPf: PartialFunction[(String, String), (String, String)] =
{case (k, v) if pf.isDefinedAt(v) => (k, pf(v))}
Another option, without creating a composed function, is this:
m.filter(e => pf.isDefinedAt(e._2)).mapValues(pf)
There is a function in Scalaz, that does exactly that: second
scala> m collect pf.second
res0: scala.collection.immutable.Map[String,String] = Map(a -> 11)
This works, because PartialFunction is an instance of Arrow (a generalized function) typeclass, and second is one of the common operations defined for arrows.