简体   繁体   English

使用复杂的累加器折叠/减少

[英]fold/reduce with complex accumulator

I have a list that looks like this:我有一个看起来像这样的列表:

val myList = listOf(
    Message(
      id= 1,
      info = listOf(1, 2)
    ),
    Message(
      id= 1,
      info = listOf(3, 4)
    ),
    Message(
      id= 2,
      info = listOf(5, 6)
    ) 
)

How can I convert it so the elements with the same id are combined?如何转换它以便合并具有相同 id 的元素?

listOf(
    Message
      id= 1
      info = listOf(1, 2, 3, 4)
    ),
    Message
      id= 2
      info = listOf(5, 6)
    ) 
)

I've tried the following, and it works我试过以下方法,它有效


myList
    .groupBy { it.id }   
    .map { entry ->
        val infos = entry.value.fold(listOf<Int>()) { acc, e -> acc + e.info }

        Message(
            id = entry.key,
            info = infos
        )
    }

But I was wondering if there was an easier/cleaner/more idiomatic way to merge these objects.但我想知道是否有更简单/更干净/更惯用的方式来合并这些对象。 It seems like I would be able to do this with a single fold, but I can't wrap my brain around it.似乎我可以通过一次折叠来完成此操作,但我无法全神贯注。

Thanks谢谢

You can groupingBy the ids, then reduce , which would perform a reduction on each of the groups.您可以按 id groupingBy ,然后进行reduce ,这将对每个组执行归约。

myList.groupingBy { it.id }.reduce { id, acc, msg -> 
    Message(id, acc.info + msg.info) 
}.values

This will of course create lots of Message and List objects, but that's the way it is, since both are immutable.这当然会创建很多MessageList对象,但事实就是如此,因为它们都是不可变的。 But there is also a chance that this doesn't matter in the grand scheme of things.但也有可能这在宏伟的计划中并不重要。

If you had a MutableMessage like this:如果您有这样的MutableMessage

data class MutableMessage(
    val id: Int,
    val info: MutableList<Int>
)

You could do:你可以这样做:

myList.groupingBy { it.id }.reduce { _, acc, msg ->
    acc.also { it.info.addAll(msg.info) }
}.values

Would also go for groupingBy but do it a bit differently via fold (compare also Grouping ):也将 go 用于groupingBy但通过fold做的有点不同(也比较Grouping ):

myList.groupingBy { it.id }
      .fold({ _, _ -> mutableListOf<Int>() }) { _, acc, el ->
        acc.also { it += el.info }
      }
      .map { (id, infos) -> Message(id, infos) }

This way you have only 1 intermediate map and only 1 intermediate list per key, which accumulates your values.这样你只有 1 个中间 map 并且每个键只有 1 个中间列表,它会累积你的值。 At the end you transform it in the form you require (eg into a Message ).最后,您将其转换为您需要的形式(例如转换为Message )。 Maybe you do not even need that?也许你甚至不需要那个? Maybe the map is already what you are after?也许 map 已经是你想要的了?

In that case you may want to use something as follows (ie narrowing the mutable list type of the values):在这种情况下,您可能希望使用如下内容(即缩小值的可变列表类型):

val groupedMessages : Map<Int, List<Int>> = myList.groupingBy { it.id }
    .fold({ _, _ -> mutableListOf() }) { _, acc, el ->
      acc.also { it += el.info }
    }

A solution without using reduce or fold:不使用 reduce 或 fold 的解决方案:

data class Message(val id: Int, val info: List<Int>)

val list = listOf(
  Message(id = 1, info = listOf(1, 2)),
  Message(id = 1, info = listOf(3, 4)),
  Message(id = 2, info = listOf(5, 6))
)

val result = list
  .groupBy { message -> message.id }
  .map { (_, message) -> message.first().copy(info = message.map { it.info }.flatten() ) }

result.forEach(::println)

By extracting out a few functions which have a meaning of their own , You can make it readable to a great extent.通过抽取出几个有自己含义的函数,可以在很大程度上让它具有可读性。

data class Message(val id: Int, val info: List<Int>) {
    fun merge(that: Message): Message = this.copy(info = this.info + that.info)
}

fun List<Message>.mergeAll() =
    this.reduce { first, second -> first.merge(second) }

fun main() {
    val myList = listOf(
        Message(
            id = 1,
            info = listOf(1, 2)
        ),
        Message(
            id = 1,
            info = listOf(3, 4)
        ),
        Message(
            id = 2,
            info = listOf(5, 6)
        )
    )

    val output = myList
        .groupBy { it.id }
        .values
        .map { it.mergeAll() }

    println(output)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 减少/折叠中的两个累加器 - Two accumulators in reduce / fold Kotlin:Lambdas、范围、映射、过滤和减少/折叠 - Kotlin: Lambdas, range, map, filter and reduce/fold 如何使用 reduce 或 fold 返回 IntArray? - How I can return IntArray with reduce or fold? 如何在 kotlin 的分组中使用折叠和减少 - how to use fold and reduce in grouping in kotlin Kotlin:如何使用带有数据结构的 reduce/fold 作为累积参数? - Kotlin: how to use reduce/fold with a data structure as the accumulative argument? 不知道为什么 collection fold 和 reduce 不等价 - Can't tell why collection fold and reduce aren't equivalent Kotlin 中 fold 和 reduce 的区别,什么时候使用? - Difference between fold and reduce in Kotlin, When to use which? 在这个使用 reduce() 内部迭代器 function 的示例中,为什么累加器不确认这个数字? - In this example using the reduce() internal iterator function, why won't the accumulator acknowledge this digit? Kotlin-使用Lambda函数进行范围,映射,过滤,缩小/折叠来查找1-1000之间所有可被3或5整除的数字之和 - Kotlin - using Lambda functions range, map, filter, reduce/fold to find the sum of all numbers between 1-1000 that are divisible by 3 or 5 折叠清单与Kotlin中的销毁任务配对 - Fold list to pair with destructuring assignment in kotlin
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM