Reputation: 1598
Given the following code:
val m: Map[String, Int] = .. // fetch from somewhere
val keys: List[String] = m.keys.toList
val keysSubset: List[String] = ... // choose random keys
We can define the following method:
def sumValues(m: Map[String, Int], ks: List[String]): Int =
ks.map(m).sum
And call this as:
sumValues(m, keysSubset)
However, the problem with sumValues
is that if ks
happens to have a key not present on the map, the code will still compile but throw an exception at runtime. Ex:
// assume m = Map("two" -> 2, "three" -> 3)
sumValues(m, 1 :: Nil)
What I want instead is a definition for sumValues
such that the ks
argument should, at compile time, be guaranteed to only contain keys that are present on the map
. As such, my guess is that the existing sumValues
type signature needs to accept some form of implicit evidence that the ks
argument is somehow derived from the list of keys of the map.
I'm not limited to a scala Map
however, as any record-like structure would do. The map structure however won't have a hardcoded value, but something derived/passed on as an argument.
Note: I'm not really after summing the values, but more of figuring out a type signature for sumValues
whose calls to it can only compile if the ks
argument is provably from the list of keys the map (or record-like structure).
Upvotes: 1
Views: 322
Reputation: 727
Another solution could be to map only the intersection (i.e. : between m
keys and ks
).
For example :
scala> def sumValues(m: Map[String, Int], ks: List[String]): Int = {
| m.keys.filter(ks.contains).map(m).sum
| }
sumValues: (m: Map[String,Int], ks: List[String])Int
scala> val map = Map("hello" -> 5)
map: scala.collection.immutable.Map[String,Int] = Map(hello -> 5)
scala> sumValues(map, List("hello", "world"))
res1: Int = 5
I think this solution is better than providing a default value because more generic (i.e. : you can use it not only with sums). However, I guess that this solution is less effective in term of performance because the intersection.
EDIT : As @jwvh pointed out in it message below, ks.intersect(m.keys.toSeq).map(m).sum
is, to my opinion, more readable than m.keys.filter(ks.contains).map(m).sum
.
Upvotes: 1