【问题标题】:What is the use case for flatMap vs map in kotlinkotlin中flatMap vs map的用例是什么
【发布时间】:2019-02-04 06:54:24
【问题描述】:

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

它有使用flatMapmap的示例

似乎两者都在做同样的事情,是否有示例显示使用 flatMapmap 的区别?

数据类型:

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
}

样本:

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()
}

【问题讨论】:

    标签: collections kotlin flatmap


    【解决方案1】:

    考虑以下示例:您有一个简单的数据结构 Data,其中包含一个类型为 List 的属性。

    class Data(val items : List<String>)
    
    val dataObjects = listOf(
        Data(listOf("a", "b", "c")), 
        Data(listOf("1", "2", "3"))
    )
    

    flatMapmap

    使用flatMap,您可以将多个Data::items“展平”到一个集合中,如items 变量所示。

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

    另一方面,使用map 只会产生一个列表列表。

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

    flatten

    Iterable&lt;Iterable&lt;T&gt;&gt;Array&lt;Array&lt;T&gt;&gt; 上还有一个flatten 扩展名,您可以在使用这些类型时替代flatMap

    val nestedCollections: List<Int> = 
        listOf(listOf(1,2,3), listOf(5,4,3))
            .flatten() //[1, 2, 3, 5, 4, 3]
    

    【讨论】:

    • flatten vs flatMap有什么用?
    • flatMap(function)map(function).flatten() 相同
    【解决方案2】:

    这里有三个功能。 ma​​p()flatten()和前两者的组合flatMap()

    考虑以下示例

    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)
    

    地图

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

    Map 允许您访问 {allHeroes} 中的每个宇宙并(在这种情况下)返回 它的英雄名单。所以输出将是一个包含两个英雄列表的列表, 每个宇宙一个。 结果是一个列表>

    平面图

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

    FlatMap 允许你做和地图一样的事情,从 两个宇宙。但它更进一步并展平了返回的列表列表 到一个列表中。 结果是一个列表

    展平

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

    这会产生与 flatMap 相同的结果。 所以 flatMap 是两个函数的组合,map{} 然后 flatten()

    【讨论】:

    • .map{ f }.flatten() 与 .flatMap{ f } 之间是否存在性能差异?
    • cmiiw 前者:O(2n) 时间复杂度(在 .map 上执行第一个 n 然后 .flatten)后者:O(n) 时间复杂度 @KristopherNoronha
    • @mochadwi 我认为 O 表示法忽略了常数,所以就时间而言两者都是 O(n) ......但是我怀疑内存/临时对象可能会描绘一个不同的故事,这可能是处理大型结构时的差异化因素。
    • 同意,实际的区别因素是空间限制
    猜你喜欢
    • 2014-02-04
    • 2019-10-10
    • 2020-12-22
    • 2014-04-16
    • 1970-01-01
    • 2014-05-15
    • 2019-12-20
    • 2022-10-13
    • 2014-12-28
    相关资源
    最近更新 更多