flatMap (was: Updated Java 8 Stream examples in GS Collections Kata)
Sam Pullara
spullara at gmail.com
Tue Nov 13 09:33:24 PST 2012
Honestly I would have expected only a single shape for flatMap:
> Stream<V> flatMap(Mapper<T, Stream<V>>)
Where the result is a concatenation of the Streams returned. Kind of like doing a map from T to Stream<V> ending up with a Stream<Stream<V>> and then calling flatten() on that Stream. Is this not the normal definition? Here is the definition from Scala:
def
flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Traversable[B]
[use case]
Builds a new collection by applying a function to all elements of this traversable collection and using the elements of the resulting collections.
For example:
def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+")
The type of the resulting collection is guided by the static type of traversable collection. This might cause unexpected results sometimes. For example:
// lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set
def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet)
// lettersOf will return a Set[Char], not a Seq
def lettersOf(words: Seq[String]) = words.toSet flatMap (word => word.toSeq)
// xs will be a an Iterable[Int]
val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2)
// ys will be a Map[Int, Int]
val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2)
B
the element type of the returned collection.
f
the function to apply to each element.
returns
a new traversable collection resulting from applying the given collection-valued function f to each element of this traversable collection and concatenating the results.
Definition Classes
TraversableLike → GenTraversableLike → FilterMonadic
Sam
On Nov 13, 2012, at 7:42 AM, Brian Goetz <brian.goetz at oracle.com> wrote:
>> The things I found awkward using in the kata were flatMap
>
> This is a complaint we received over and over again in the "Hack Day" sessions -- it is pretty clear we are not there yet on flatMap.
>
> 1. It is not obvious flatMap is the best name, as it sets expectations for Scala users that will not be met. Perhaps mapMulti? explode?
>
> 2. The API form is definitely not there yet. But, the "obvious" suggestion is clearly wrong. Assume for sake of argument that there will be only one version of flatMap. What everyone thinks it should look like (after a few seconds of thought) is:
>
> Stream<T> flatMap(Mapper<T, Collection<T>>)
>
> But, this is awful (except when you already happen to have a Collection lying around, which will be sometimes but by no means all of the time.) This forces (a) the client to create and populate a Collection in the lambda (yuck!), usually an extra collection to be created even when the element maps to nothing, and then forces an iteration (with Iterator) on the other side. So, in the case where there's no collection lying around, the client code is larger, uglier, and in any case the whole thing is significantly slower. The current version has a very nice property: when the element maps to nothing, there's no work to do.
>
> This is further challenging because of erasure. If we had:
>
> Stream<T> flatMap(Mapper<T, Collection<T>>)
>
> we might also want
>
> Stream<T> flatMap(Mapper<T, T[]>)
> or
> Stream<T> flatMap(Mapper<T, Stream<T>>)
> or
> Stream<T> flatMap(Mapper<T, Streamable<T>>)
>
> But, we can't overload these since their erasure is all "Mapper".
>
>
More information about the lambda-libs-spec-observers
mailing list