【问题标题】:Kotlin: transform a list of objects into a map of object propertiesKotlin:将对象列表转换为对象属性映射
【发布时间】:2018-12-12 05:07:31
【问题描述】:

使用以下数据类:

data class Photo(val id: String)
data class Album(val id: String, val photos: List<Photo>)

我希望能够将Albums 的列表转换为Map&lt;photoId, Set&lt;albumId&gt;&gt; 的地图

例如:

val albums = listOf(
    Album("1", listOf(
        Photo("1"),
        Photo("2"),
        Photo("3")
    )),
    Album("2", listOf(
        Photo("1"),
        Photo("2")
    ))
)

会变成:

val map = mapOf(
    Pair("1", setOf("1", "2")),
    Pair("2", setOf("1", "2")),
    Pair("3", setOf("1")
)

有没有办法使用 kotlin 转换函数/lambdas 来做到这一点?例如,groupBy、flatMap?

【问题讨论】:

    标签: function lambda kotlin


    【解决方案1】:

    更清洁的解决方案

    val grouped = albums
        .flatMap { album -> album.photos.map { photo -> Pair(photo.id, album.id) } }
        .groupBy( { (photoId, _) -> photoId }, { (_, albumId) -> albumId } )
        .mapValues { it.value.toSet() }
    

    并检查正确性

    val map = mapOf(
        Pair("1", setOf("1", "2")),
        Pair("2", setOf("1", "2")),
        Pair("3", setOf("1"))
    )
    
    check(map == grouped) // Success
    

    一点解释

    • 使用第一个 flatMap,我们将 专辑 列表 (List&lt;Album&gt;) 转换为 List&lt;Pair&lt;String, String&gt;&gt;photo.idalbum.id)。

      李>
    • 使用groupBy,我们将第二个列表转换为Map&lt;String, List&lt;String&gt;&gt;,其中键为photo.id,并按album..id分组

    • 使用mapValues,我们将地图转换为Map&lt;String, Set&lt;String&gt;&gt;

    【讨论】:

    • 哇,更好的解决方案(鼓掌)!考虑(照片和相册的)关系而不是对象(照片)!
    • 感谢您的解决方案!
    【解决方案2】:

    一个肮脏的解决方案:

    val map = albums.map {
        it.photos.map { it.id } // get all photos in all album
    }.flatten() // into a single list (instead of 2-d list)
        .toSet() // remove duplicates
        .associate { photo ->
            photo to albums.filter { it.photos.contains(Photo(photo)) } // for each photo, find its existance in all albums
                .map { it.id }.toSet() // output album ids
        }
    

    【讨论】:

    • 感谢您的回答,对不起,如果这是一个愚蠢的问题,但是为什么这被认为是“肮脏”的解决方案?
    • @oznecro 因为我认为可能有一个“纯”解决方案,只需输入一次albums,然后将它们传递给整个函数,但我的解决方案需要两次。 (不过,这可能是我自己对“纯函数式编程”中的“纯”的误解。)另外,使用.apply {}可以避免这种情况,但我认为它不是那么清楚。
    猜你喜欢
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 2019-01-16
    相关资源
    最近更新 更多