fold/reduce 复杂累加器
fold/reduce with complex accumulator
我有一个如下所示的列表:
val myList = listOf(
Message(
id= 1,
info = listOf(1, 2)
),
Message(
id= 1,
info = listOf(3, 4)
),
Message(
id= 2,
info = listOf(5, 6)
)
)
如何转换它以便合并具有相同 id 的元素?
listOf(
Message
id= 1
info = listOf(1, 2, 3, 4)
),
Message
id= 2
info = listOf(5, 6)
)
)
我试过以下方法,效果很好
myList
.groupBy { it.id }
.map { entry ->
val infos = entry.value.fold(listOf<Int>()) { acc, e -> acc + e.info }
Message(
id = entry.key,
info = infos
)
}
但我想知道是否有 easier/cleaner/more 惯用的方法来合并这些对象。貌似单折就可以了,但是脑子转不过来
谢谢
您可以groupingBy
the ids, then reduce
,这将对每个组执行缩减。
myList.groupingBy { it.id }.reduce { id, acc, msg ->
Message(id, acc.info + msg.info)
}.values
这当然会创建很多 Message
和 List
对象,但事实就是如此,因为它们都是不可变的。但也有可能这在宏伟的计划中并不重要。
如果你有这样的MutableMessage
:
data class MutableMessage(
val id: Int,
val info: MutableList<Int>
)
你可以这样做:
myList.groupingBy { it.id }.reduce { _, acc, msg ->
acc.also { it.info.addAll(msg.info) }
}.values
不使用 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)
通过抽取出几个函数有自己的意义,可以大大提高可读性。
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)
}
也会选择 groupingBy
but do it a bit differently via fold
(compare also Grouping
):
myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf<Int>() }) { _, acc, el ->
acc.also { it += el.info }
}
.map { (id, infos) -> Message(id, infos) }
这样你只有 1 个中间映射,每个键只有 1 个中间列表,它会累积你的值。最后,您将其转换为您需要的形式(例如转换为 Message
)。也许你甚至不需要那个?也许地图已经是你想要的了?
在这种情况下,您可能希望使用如下内容(即缩小值的可变列表类型):
val groupedMessages : Map<Int, List<Int>> = myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf() }) { _, acc, el ->
acc.also { it += el.info }
}
我有一个如下所示的列表:
val myList = listOf(
Message(
id= 1,
info = listOf(1, 2)
),
Message(
id= 1,
info = listOf(3, 4)
),
Message(
id= 2,
info = listOf(5, 6)
)
)
如何转换它以便合并具有相同 id 的元素?
listOf(
Message
id= 1
info = listOf(1, 2, 3, 4)
),
Message
id= 2
info = listOf(5, 6)
)
)
我试过以下方法,效果很好
myList
.groupBy { it.id }
.map { entry ->
val infos = entry.value.fold(listOf<Int>()) { acc, e -> acc + e.info }
Message(
id = entry.key,
info = infos
)
}
但我想知道是否有 easier/cleaner/more 惯用的方法来合并这些对象。貌似单折就可以了,但是脑子转不过来
谢谢
您可以groupingBy
the ids, then reduce
,这将对每个组执行缩减。
myList.groupingBy { it.id }.reduce { id, acc, msg ->
Message(id, acc.info + msg.info)
}.values
这当然会创建很多 Message
和 List
对象,但事实就是如此,因为它们都是不可变的。但也有可能这在宏伟的计划中并不重要。
如果你有这样的MutableMessage
:
data class MutableMessage(
val id: Int,
val info: MutableList<Int>
)
你可以这样做:
myList.groupingBy { it.id }.reduce { _, acc, msg ->
acc.also { it.info.addAll(msg.info) }
}.values
不使用 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)
通过抽取出几个函数有自己的意义,可以大大提高可读性。
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)
}
也会选择 groupingBy
but do it a bit differently via fold
(compare also Grouping
):
myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf<Int>() }) { _, acc, el ->
acc.also { it += el.info }
}
.map { (id, infos) -> Message(id, infos) }
这样你只有 1 个中间映射,每个键只有 1 个中间列表,它会累积你的值。最后,您将其转换为您需要的形式(例如转换为 Message
)。也许你甚至不需要那个?也许地图已经是你想要的了?
在这种情况下,您可能希望使用如下内容(即缩小值的可变列表类型):
val groupedMessages : Map<Int, List<Int>> = myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf() }) { _, acc, el ->
acc.also { it += el.info }
}