-
Notifications
You must be signed in to change notification settings - Fork 72
Map functional combinators #71
Comments
Some random thoughts:
|
They work key-by-key. If you don't have maps, you don't have keys. Also, because they work key-by-key, they are exactly analogous to a zip except instead of going by index, they go by key (which is the only sane thing to do anyway--zip on two sets makes very little sense). |
@julienrf following your questions order:
As an example: In relation to the access-element by index (From a logical standpoint, saving all other differences): Couldn't a |
I was curious about how did they do this in Haskell, as a matter of fact, the Quite similar to def mergeByKeyWith[W, X](that: Map[K, W](f: PartialFunction[(Option[V], Option[W]), X]: Map[K, X] With the main different that it encodes the behaviour to apply under the three matching possibilities with three separated functions:
|
That would probably be more efficient since it would avoid creating tuples and However, wouldn't it make more sense to introduce an |
@LPTK At the end of the day those Haskell's "tactics" wrap functions returning Would I understand the raison d'etre of |
@pfcoperez Both cats and scalaz have an EitherOrBoth of some kind (Ior and \&/) so it's reasonable to assume that people find them useful |
@DavidGregory084 That's great! I didn't know it was a thing people used and if it was available it would be nice to apply @LPTK 's idea to have something like: def mergeByKeyWith[W, X](that: Map[K, W](f: PartialFunction[EitherOrBoth[V,W], X]): Map[K, X] I am also concerned about the discussed operation set performance: def zipByKeyWith[W, X](that: Map[K, W])(f: (V, W) => X): Map[K, X] =
for((k,va) <- this; vb <- that.get(k)) yield k -> f(va, vb) On the other hand, As described in the use case of the issue, you could implement left join using There are several approaches to avoid this but the idea of the three functions to encode the three behaviours could be rescued and expanded into: three partial functions: def mergeByKeyWith[W, X](that: Map[K, W])(
justLeft: PartialFunction[V, X] = PartialFunction.empty)(
justRight: PartialFunction[W, X] = PartialFunction.empty)(
both: PartialFunction[(V, W), X] = PartialFunction.empty
): Map[K, X] Given that the passed partial function might be def mergeByKeyWith[W, X](that: Map[K, W])(
justLeft: PartialFunction[V, X] = PartialFunction.empty)(
justRight: PartialFunction[W, X] = PartialFunction.empty)(
both: PartialFunction[(V, W), X] = PartialFunction.empty
): Map[K, X] = { // Naive - and not compiled- implementation, just to illustrate
val masterKey = keys ++ {
if(justRight != PartialFunction.empty) that.keys
else Iterable.empty
}
for(k <- masterKey; ova <- get(k); ovb <- that.get(k)) yield {
...
...
...
}
} Better performance left outer join: def leftOuterJoin[K, VA, VB](a: Map[K, VA], b: Map[K, VB]): Map[K, (VA, Option[VB])] =
a.mergeByKeyWith(b) { case va => va -> None } () { case (va, vb) => va -> Some(vb) } |
Last year I opened a PR to Scala 2.12 aimed to include a join like operation subset within
Map
operations set:scala/scala#5353
After some discussion it was clear that a more functional interface would fit better with the current map collections interface as
join
methods belong to the foreign (and not so abstract) realm of databases operations.That was thoroughly syntetized by @szeiger 's comment, who proposed the following operation set:
And, to be able to handle non matching - in both maps - keys:
merge*
would then be the way to provide left/right/full-outer join logical operations.How could join operations be expressed using this API?
(NOTE: This is an application example, not part of the requested functionality)
I think
mergeByKey*
operations are important as they cover all outer cases. In fact,zipByKeyWith
implementation could be:But I wouldn't use that implementation since, provided you're zipping only matching keys, you could avoid scrutinising
that
key set.The text was updated successfully, but these errors were encountered: