Reputation: 9986
Let there is a map config: Map[String, String]
.
And there are several keys: "foo", "bar", ...
I need to make sure that all keys are present in config
. And if they are present, I need to call a function with values for these keys in the config
map:
fun(config("foo"), config("bar"), config(...), ...)
The following is a solution:
val res = Option.when(config.contains("foo") & config.contains("bar") & config.contains(...) & ...)
( fun(config("foo"), config("bar"), config(...), ...) )
Or maybe:
val set = Set("foo", "bar", ...)
val res = Option.when(config.view.filterKeys(set).size == set.size)
( fun(config("foo"), config("bar"), config(...), ...) )
Both approaches look ugly and ineffective. Is there more concise way to implement the same behavior?
Upvotes: 0
Views: 496
Reputation: 9986
The following is a flatMap
way:
config.get("key1").flatMap(key1 =>
config.get("key2").flatMap(key2 =>
...
config.get("keyN").flatMap(keyN =>
fun(key1, key2, ..., keyN)
))...)
Upvotes: 0
Reputation: 48400
Consider forall
in combination with contains
val requiredKeys = List("foo", "bar")
if (requiredKeys forall config.contains) {
// work with config
} else {
// handler error
}
or based on Tom Crockett consider keySet
approach
val requiredKeys = Set("foo", "bar")
if (requiredKeys subsetOf config.keySet) {
// work with config
} else {
// handler error
}
Upvotes: 1
Reputation: 1678
This is using cats, a very common FP library:
import cats.implicits._
def fun(a: String, b: String, c: String): MyConfigClass = ???
val parsedOpt: Option[MyConfigClass] =
(config.get("a"), config.get("b"), config.get("c"))
.mapN(fun)
The mapN
method does what you want, it will extact all values if they exist and provide them to fun. For the curious, it relies on the fact that Option
is an Applicative
.
To show its power, you could also get back a list of missing keys, to know where the issue was:
import cats.data._
def getConfig(key: String): Either[NonEmptyList[String], String] =
config.get(key).toRightNel(s"Key $key not found")
val parsedValidated: Either[NonEmptyList[String], MyConfigClass] =
(getConfig("a"), getConfig("b"), getConfig("c"))
.parMapN(fun)
Upvotes: 0
Reputation: 22840
Since the set of keys is static, you do not need to do anything too complex.
You just need to attempt to get each key and if all are in call the function and wrap the result in a Some, if not then return a None.
for {
value1 <- config.get("key1")
// ...
valueN <- config.get("keyN")
} yield fun(value1, ..., valueN)
If you have cats, you can do it like.
(
config.get("key1"),
// ...
config.get("keyN")
).mapN(fun(_).tupled)
Upvotes: 2
Reputation: 6637
if you have your keys as ("foo", "bar", ...).map(config) returns the values, right? then if it contains a None, then not all keys are found. I would start to think along this idea.
Passing elements of a List as parameters to a function with variable arguments helps here, so val args = list.map(config); then the condition to check if all values are present, and finally fun(args:_*).
how about that?
Upvotes: 0