Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the use case for flatMap vs map in kotlin

in https://try.kotlinlang.org/#/Kotlin%20Koans/Collections/FlatMap/Task.kt

it has sample of using flatMap and map

seems both are doing the same thing, is there a sample to show the difference of using flatMap and map?

the data type:

data class Shop(val name: String, val customers: List<Customer>)

data class Customer(val name: String, val city: City, val orders: List<Order>) {
    override fun toString() = "$name from ${city.name}"
}

data class Order(val products: List<Product>, val isDelivered: Boolean)

data class Product(val name: String, val price: Double) {
    override fun toString() = "'$name' for $price"
}

data class City(val name: String) {
    override fun toString() = name
}

the samples:

fun Shop.getCitiesCustomersAreFrom(): Set<City> =
    customers.map { it.city }.toSet()
    // would it be same with customers.flatMap { it.city }.toSet() ?

val Customer.orderedProducts: Set<Product> get() {
    return orders.flatMap { it.products }.toSet()
    // would it be same with return orders.map { it.products }.toSet()
}
like image 756
lannyf Avatar asked Aug 29 '18 13:08

lannyf


People also ask

What is difference between map and flatMap in Kotlin?

Conclusion: FlatMap is used to combine all the items of lists into one list. Map is used to transform a list based on certain conditions.

Should I use map or flatMap?

You should use a map() if you just want to transform one Stream into another where each element gets converted to one single value. Use flatMap() if the function used by map operation returns multiple values and you want just one list containing all values.

What is difference between flatMap () and map () functions?

Both of the functions map() and flatMap are used for transformation and mapping operations. map() function produces one output for one input value, whereas flatMap() function produces an arbitrary no of values as output (ie zero or more than zero) for each input value. Where R is the element type of the new stream.

What is the use of flatMap?

In short, we can say that the flatMap() method helps in converting Stream<Stream<T>> to Stream<T>. It performs flattening (flat or flatten) and mapping (map), simultaneously. The Stream. flatMap() method combines both the operations i.e. flat and map.


2 Answers

Consider the following example: You have a simple data structure Data with a single property of type List.

class Data(val items : List<String>)

val dataObjects = listOf(
    Data(listOf("a", "b", "c")), 
    Data(listOf("1", "2", "3"))
)

flatMap vs. map

With flatMap, you can "flatten" multiple Data::items into one collection as shown with the items variable.

val items: List<String> = dataObjects
    .flatMap { it.items } //[a, b, c, 1, 2, 3]

Using map, on the other hand, simply results in a list of lists.

val items2: List<List<String>> = dataObjects
    .map { it.items } //[[a, b, c], [1, 2, 3]] 

flatten

There's also a flatten extension on Iterable<Iterable<T>> and also Array<Array<T>> which you can use alternatively to flatMap when using those types:

val nestedCollections: List<Int> = 
    listOf(listOf(1,2,3), listOf(5,4,3))
        .flatten() //[1, 2, 3, 5, 4, 3]
like image 67
s1m0nw1 Avatar answered Oct 16 '22 13:10

s1m0nw1


There are three functions in play here. map(), flatten(), and flatMap() which is a combination of the first two.

Consider the following example

data class Hero (val name:String)
data class Universe (val heroes: List<Hero>)
    
val batman = Hero("Bruce Wayne")
val wonderWoman = Hero (name = "Diana Prince")
    
val mailMan = Hero("Stan Lee")
val deadPool = Hero("Wade Winston Wilson")
    
val marvel = Universe(listOf(mailMan, deadPool))
val dc = Universe(listOf(batman, wonderWoman))
    
val allHeroes: List<Universe> = listOf(marvel, dc)

Map

allHeroes.map { it.heroes }
// output: [[Hero(name=Stan Lee), Hero(name=Wade Winston Wilson)], [Hero(name=Bruce Wayne), Hero(name=Diana Prince)]]

Map allows you to access each universe in {allHeroes} and (in this case) return its list of heroes. So the output will be a list containing two lists of heroes, one for each universe. The result is a List<List>

Flatmap

allHeroes.flatMap { it.heroes } 
// output: [Hero(name=Stan Lee), Hero(name=Wade Winston Wilson), Hero(name=Bruce Wayne), Hero(name=Diana Prince)]

FlatMap allows you to do the same as map, access the two lists of heroes from both universes. But it goes further and flattens the returned list of lists into a single list. The result is a List

Flatten

allHeroes.map { it.heroes }.flatten() 
// output: [Hero(name=Stan Lee), Hero(name=Wade Winston Wilson), Hero(name=Bruce Wayne), Hero(name=Diana Prince)]

This produces the same result as flatMap. So flatMap is a combination of the two functions, map{} and then flatten()

like image 36
Dawit Abraham Avatar answered Oct 16 '22 12:10

Dawit Abraham