is it possible to match Option[Map[String,String]] for some key at once (e.g. without nested matches)?
The following snippet is how it is now:
val myOption:Option[Map[String,String]] = ...
myOption match {
case Some(params) =>
params get(key) match {
case Some(value) => Ok(value)
case None => BadRequest
case None => BadRequest
}
Sure! Just flatMap that sh*t!
def lookup(o: Option[Map[String, String]], k: String) =
o.flatMap(_ get k).map(Ok(_)).getOrElse(BadRequest)
If you're using Scala 2.10 you can fold over the Option:
def lookup(o: Option[Map[String, String]], k: String) =
o.flatMap(_ get k).fold(BadRequest)(Ok(_))
(for (params <- myOption; value <- params.get(key)) yield Ok(value)).getOrElse(BadRequest)
You should be able to do this using a couple of higher-order functions. I think this does what you want:
myOption.collect {
case m if (m contains key) => Ok(m(key))
} getOrElse BadRequest
collect takes a partial function, and the getOrElse handles the case where the partial function returned None, which translates it to your BadRequest case.
Related
There is simple abstract look up service with possibility to retrieve value by key:
trait LookUp[F[_]] {
def read(key: String): F[Option[String]]
}
There is use case of this service, idea is to give implemented storage and accumulator with starting key, then ask for value from db if the result is None then stop and Return None, if the value is found then add it to accumulator list and look up for next value as key from previous call result. Execution stops when retrieved value already is found before or None is retrieved. Then a string of all acc elements is returned as result.
Tried like this:
def readWhileFound[F[_]: Monad](db: LookUp[F], acc: List[String]): F[Option[String]] = {
for{ result <- db.read(acc.head)} yield result match {
case Some(value) if(!acc.contains(value)) => readWhileFound(db, value::acc)
case _ => acc.mkstring("")
}
}
But I'm not able to get types right getting mismatch errors like:
found : F[cats.data.OptionT[[_]F[_],String]]
required: cats.data.OptionT[F,String]
Approach number 2:
def readWhileFound[F[_]: Monad](key: String, db: LookUp[F])(implicit m: Monad[F]): F[Option[String]] = {
m.tailRecM((Option(key), List.empty[String])) { case (currentK, accum) =>
currentK match {
case Some(value) if(!accum.contains(value)) => m.pure(Left((db.read(value), value :: accum)))
case _ => m.pure(Right(Some(accum.mkString(""))))
}
}
}
Getting compiler error:
(Found) F[Option[String]]
required: Option[String]
case Some(value) if(!accum.contains(value)) => m.pure(Left((db.read(value), value :: accum)))
Looks like db.read(value) somehow should be unwrapped out of F
This looks like a great use case for fs2:
You should be able to do something like this:
import fs2.Stream
def readWhileFound[F[_]: Concurrent](db: LookUp[F])(initialKey: String): F[List[String] =
Stream.unfoldEval(initialKey) { currentKey =>
db.read(key = currentKey).map(k => (k, k))
}.compile.toList
You are match-ing on the wrong expression in your first implementation. You should match on result, not on the entire for-comprehension. The implementation below should do what you're after.
def readWhileFound[F[_]: Monad](db: LookUp[F], startKey: String): F[Option[String]] = {
def loop(currKey: String, seenKeys: Set[String]): F[Option[String]] = {
db.read(currKey).flatMap {
case Some(nextKey) if !seenKeys.contains(nextKey) =>
loop(nextKey, seenKeys + nextKey)
case _ if seenKeys.nonEmpty => seenKeys.mkString("").some.pure[F]
case _ => none[String].pure[F]
}
}
loop(startKey, Set.empty)
}
I've replaced List with Set for the accumulated values because its contains method is more efficient, but if you care about the order in the returned result then you'll have to either go back to List (less efficient) or use two accumulators (one Set, the other List).
I'm trying to match an enum value converted to a string held in a collection. Here's the code:
object Foo extends Enumeration {
val ONE = Value("ONE")
val TWO = Value("TWO")
}
def check(seq: Seq[String]): Unit = seq match {
case Seq(Foo.ONE.toString) => println("match")
case _ => println("no match")
}
This results in a compilation error:
error: stable identifier required, but Foo.ONE.toString found.
case Seq(Foo.ONE.toString) => println("match")
What is the proper way to use my Foo enumerated values as elements of my pattern matching case statements?
Map it back to the enum first:
import scala.util.Try
val enumSeq = seq map (x => Try(Foo.withName(x)))
Then you can either filter out the Failures or match on Seq(Success(ONE)), Seq(Success(ONE)), ..., Seq(Failure), etc.
def check(seq: Seq[String]): Unit = seq match {
case Seq(s # _) if s == Foo.ONE.toString => println("match")
case _ => println("no match")
}
I like the response from #cchantep, which was to avoid calling .toString inside the pattern match and implement the check method like so:
def check(seq: Seq[Foo.Value]): Unit = seq match {
case Seq(Foo.ONE) => println("match")
case _ => println("no match")
}
I have a function which converts an option containing an empty sequence to None:
def emptyToNone[A](seqOpt: Option[Seq[A]]): Option[Seq[A]] = seqOpt match {
case Some(Seq()) => None
case _ => seqOpt
}
I would like to make it more general by replacing Seq with a type parameter, so it can be used with other Scala collections.
I was able to do it like this:
def emptyToNone[C[A] <: Traversable[A], A](seqOpt: Option[C[A]]): Option[C[A]] = seqOpt match {
case Some(s) if s.isEmpty => None
case _ => seqOpt
}
But I had to use 2 type parameters, C and A. Can I simplify function signature here?
Edit: Modified to include #Alexey's suggestion.
This could be one solution:
def emptyToNone[C <: Traversable[_]](seqOpt: Option[C]): Option[C] =
seqOpt.filter(_.nonEmpty)
I am porting a class from Ruby to Scala 2.11 that implements variable merging in messages. I would like to pass an array of objects to the merge method and have it search each object for the keys that are referenced in the text of the message.
The core of this is a method called lookUp(key: String, obj: AnyRef) which receives a single key for which to search, and a single object on which to search for the key. If the object is a Map, and the Map's keys are either Symbol or String, then it will look in the Map for the requested key. Otherwise it will check if the object has a method with the same name of the key, and if so, it will invoke that method.
In the existing Ruby code, it is trivially easy to do this:
def look_up(key, obj)
if obj.respond_to?(:has_key?) && obj.has_key?(key)
obj[key]
elsif obj.respond_to?(key)
obj.send(key)
elsif obj.instance_variable_defined?(ivar = "##{key}")
obj.instance_variable_get(ivar)
end
end
Since it's easy to do so, the Ruby code also looks for an instance variable of the same name. I don't necessarily need that functionality in my Scala version.
One of the issues I am having is that the examples I've found require that I know the object's class ahead of time so I can call ru.typeOf[MyClass].declaration(ru.TermName("key")) (where ru is scala.reflect.runtime.universe).
Another issue is that this message merge can be happening hundreds of times per minute, and reflection seems to be a slow, involved process. If this all works as planned, I'll likely cache the reflection results by object type.
UPDATE: I was thinking about something like this, but is this overkill? Or is it necessary to properly capture the types in the Map? Also, this doesn't compile. Map, Symbol and String aren't the right types for their context.
def lookUp[T](obj: T, key: String)(implicit tag: ru.TypeTag[T]): Option[String] = tag.tpe match {
case ru.TypeRef(a, Map, List(Symbol, _)) => if (obj.contains(Symbol(key))) Some(obj(Symbol(key)).toString) else None
case ru.TypeRef(a, Map, List(String, _)) => if (obj.contains(key)) Some(obj(key).toString) else None
case _ =>
if (/* obj.key() exists */)
// Some(obj.key().toString)
else
None
}
UPDATE 2: It never occurred to me that I could use asInstanceOf with something like Map[String, _]. I used #johny's second example of code to come up with my solution. I cache the method names by class in a mutable.HashMap[Class[_], Set[String]].
def lookUp(obj: AnyRef, key: String): Option[String] = obj match {
case m: Map[_, _] =>
if (m.asInstanceOf[Map[String, _]].contains(key))
extractValue(m.asInstanceOf[Map[String, _]](key))
else if (m.asInstanceOf[Map[Symbol, _]].contains(Symbol(key)))
extractValue(m.asInstanceOf[Map[Symbol, _]](Symbol(key)))
else
None
case _ =>
val klass = obj.getClass
if (!methodsCache.contains(klass))
methodsCache(klass) = klass.getMethods.toList.filter(_.getParameterCount == 0).map(_.getName).toSet
val methodNames = methodsCache(klass)
if (methodsCache(klass).contains(key))
extractValue(klass.getDeclaredMethod(key).invoke(obj))
else
None
}
def extractValue(obj: Any): Option[String] = obj match {
case null | None => None
case Some(x) => Some(x.toString)
case x => Some(x.toString)
}
def lookUp(key: String, obj: AnyRef) {
obj match {
case x: Map[String, _] => x(key)
case _ => obj.getClass.getDeclaredMethod(key).invoke(obj)
}
}
Edit: To make sure key of Map is either String or scala.Symbol
def lookUp(key: String, obj: AnyRef)= {
obj match {
case x: Map[_, _] =>
if(x.asInstanceOf[Map[String,_]].contains(key))
x.asInstanceOf[Map[String,_]].get(key)
else if(x.asInstanceOf[Map[scala.Symbol,_]].contains(scala.Symbol(key)))
x.asInstanceOf[Map[scala.Symbol,_]].get(scala.Symbol(key))
else
None
case _ => Some(obj.getClass.getDeclaredMethod(key).invoke(obj))
}
}
The above too doesnt make sure the returned output is from the intended Map.
Edit: Following #JimCain's lead
def lookUp[T:ru.TypeTag](obj: T, key: String): Option[Any] = ru.typeTag[T].tpe match {
case ru.TypeRef(a, m, l) if(m.name.toString=="Map"&&l.head =:= ru.typeOf[java.lang.String])=> obj.asInstanceOf[Map[String,_]].get(key)
case ru.TypeRef(a, m,l) if(m.name.toString=="Map"&&l.head =:= ru.typeOf[Symbol])=> obj.asInstanceOf[Map[Symbol,_]].get(scala.Symbol(key))
case _ => Try(obj.getClass.getDeclaredMethod(key).invoke(obj)) match {
case Success(x) => Some(x)
case Failure(_) => None
}
}
I am trying to chain together some basic functions using Futures returned from a slick action and I'm hitting some pretty trivial stumbling blocks.
Both the andThen and onSuccess methods require a PartialFunction passed as a parameter. My understanding is probably quite flawed but after reading about anonymous functions it seems like andThen needs to know your anonymous function with cater for any Success or Failure input.
Given onSuccess already only caters for the Success case why does it still need to be a PartialFunction?
This block of code my indicate the problem I am having:
val db = Database.forConfig("h2mem1")
try {
val f = db.run(setupCommands)
.onSuccess { println(_) }
Await.ready(f, 10.seconds )
}
finally db.close
I get a compile error:
[error] found : Unit => Unit
[error] required: PartialFunction[Unit,?]
[error] .onSuccess { println(_) }
They did it so you can pattern match on the result, though I agree that it seems needless, I don't really use onSuccess and prefer to map and flatMap my futures:
val f = Future.successful("test")
f.onSuccess({
case "test" => println("Worked")
case x: String => println(s"Kind of worked: $x")
})
In the case of more advanced data types I could see this being more useful:
val fOpt = Future.successful(Option("Test"))
fOpt.onSuccess({
case Some(x) => println(x)
case None => println("None")
})
Really this is probably just coming from the actor api since when you ask an actor you don't know the return type, you need to pattern match on it since it's Any:
val actor:ActorRef = ???
val fAny = actor ? "asking"
fAny.onSuccess({
case x:String => println(s"Something String $x")
case x:Int => println(s"Something Int $x")
case x => println(s"Something else $x")
})
Well, you can just pass it a PartialFunction, if it needs one:
db.run(setupCommands).onSuccess(PartialFunction(println))
Or:
db.run(setupCommands).onSuccess { case result => println(result) }