Map vs Flatmap (in reference to RxJava)
Lets start with basic understanding of map and flatmap with an example ->
val someList = listOf<Int>(1, 2, 3, 4)
val mapList = someList.map {
x -> x*2
}
val flatMapList = someList.flatMap {
x -> listOf<Int>(x * 2)
}
Both of them produce the same output -> [2, 4, 6, 8] The only difference comes between their signature.
More generically speaking:
fun <Y> map( fun (x): x): Y
fun <Y> flatMap (fun (x): Y ): Y
In the first example, Y isList<Int> and x is Int
Lets see the flatmap in javascript.
let arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
Its like, it flattens to one depth.
Now some advanced example. Flatmap in RxJava.
override fun articleDetail(id: String): Single<ArticleDetailData> {
return articleEndPoint.getArticleDetail(id)
.flatMap {
val body = it.body()
if (it.isSuccessful && body != null) {
Single.just(body.articleDetailData)
} else {
Single.error(HttpException(it))
}
}
}
articleEndPoint.getArticleDetail(id) // returns Single<Response<ArticleDetailData> > when the api is hit.
Single<Something> calls .flatMap . So we do some logic with Something here and then we have to return the Single with Single.just or Single.error (to make them into Single) as its a flatmap.
Same implementation with map:-
override fun articleDetail(id: String): Single<ArticleDetailData> {
return articleEndPoint.getArticleDetail(id)
.map {
val body = it.body()
if (it.isSuccessful && body != null) {
body.articleDetailData
} else {
error("Some HTTP Exception")
}
}
}
Here is a simple thumb-rule that I use help me decide as when to use flatMap() over map() in Rx's Observable.
Once you come to a decision that you’re going to employ a map transformation, you'd write your transformation code to return some Object right?
If what you’re returning as end result of your transformation is:
- a non-observable object then you’d use just
map(). Andmap()wraps that object in an Observable and emits it. - an
Observableobject, then you'd useflatMap(). AndflatMap()unwraps the Observable, picks the returned object, wraps it with its own Observable and emits it.
Say for example we’ve a method titleCase(String inputParam) that returns Titled Cased String object of the input param. The return type of this method can be String or Observable<String>.
- If the return type of
titleCase(..)were to be mereString, then you'd usemap(s -> titleCase(s)) - If the return type of
titleCase(..)were to beObservable<String>, then you'd useflatMap(s -> titleCase(s))