英文:
groupByTo return emptySet in Kotlin
问题
val input = "perm1|0,perm2|2,perm2|1"
val output = input.split(",")
.map { it.split("|") }
.groupByTo(
mutableMapOf(),
keySelector = { it[0] },
valueTransform = { if (it[1] != "0") setOf(it[1].toLong()) else emptySet() }
)
.mapValues { it.value.reduce { acc, set -> acc + set } }
val desiredOutput = output.map { (key, values) ->
"$key [${values.joinToString(", ")}]"
}.joinToString(", ", "{", " }")
println(desiredOutput)
英文:
I have string like this.
val input = "perm1|0,perm2|2,perm2|1"
Desired output type is
val output: Set<String, Set<Long>>
and desired output value is
{perm1 [], perm2 [1,2] }
Here I need empty set if value is 0
. I am using groupByTo
like this
val output = input.split(",")
.map { it.split("|") }
.groupByTo(
mutableMapOf(),
keySelector = { it[0] },
valueTransform = { it[1].toLong() }
)
However the output structure is like this
MutableMap<String, MutableList<Long>>
and output is
{perm1 [0], perm2 [1,2] }
I am looking for best way to get desired output without using imperative style like this.
val output = mutableMapOf<String, Set<Long>>()
input.split(",").forEach {
val t = it.split("|")
if (t[1].contentEquals("0")) {
output[t[0]] = mutableSetOf()
}
if (output.containsKey(t[0]) && !t[1].contentEquals("0")) {
output[t[0]] = output[t[0]]!! + t[1].toLong()
}
if (!output.containsKey(t[0]) && !t[1].contentEquals("0")) {
output[t[0]] = mutableSetOf()
output[t[0]] = output[t[0]]!! + t[1].toLong()
}
}
答案1
得分: 5
你可以简单地使用mapValues将值的类型从List<Long>
转换为Set<Long>
var res: Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy({ it[0] }, { it[1].toLong() })
.mapValues { it.value.toSet() }
如果你想要用空集合来替换0
的列表,可以使用if
表达式来实现
var res: Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy({ it[0] }, { it[1].toLong() })
.mapValues { if (it.value == listOf<Long>(0)) setOf() else it.value.toSet() }
英文:
You can simply use mapValues to convert values type from List<Long>
to Set<Long>
var res : Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy( {it[0]}, {it[1].toLong()} )
.mapValues { it.value.toSet() }
And of you want to replace list of 0
with empty set you can do it using if-expression
var res : Map<String, Set<Long>> = input.split(",")
.map { it.split("|") }
.groupBy( {it[0]}, {it[1].toLong()} )
.mapValues { if(it.value == listOf<Long>(0)) setOf() else it.value.toSet() }
答案2
得分: 1
注意,您不能使用带有键值对的 Set,结果将是 map 类型。下面的代码会将值按照排序后的集合方式返回。
val result = "perm1|0,perm2|2,perm2|1".split(",")
.map {
val split = it.split("|")
split[0] to split[1].toLong()
}.groupBy({ it.first }, { it.second })
.mapValues { it.value.toSortedSet() }
英文:
Note that you cannot have Set with key-value pair, result will be of type map. Below code gives sorted set in the values.
val result = "perm1|0,perm2|2,perm2|1".split(",")
.map {
val split = it.split("|")
split[0] to split[1].toLong()
}.groupBy({ it.first }, { it.second })
.mapValues { it.value.toSortedSet() }
答案3
得分: 0
以下是您要的翻译内容:
虽然其他答案可能更容易理解,它们在其中构建了立即被丢弃的列表和映射,这些列表和映射基本上在下一次操作之后就被丢弃了。以下尝试使用 splitToSequence
(Sequences) 和 groupingBy
(请参阅 分组底部部分)来避免这种情况:
val result: Map<String, Set<Long>> = input.splitToSequence(',')
.map { it.split('|', limit = 2) }
.groupingBy { it[0] }
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
it.add(element[1].toLong()))
}
}
当然,您也可以在 fold
步骤中通过一个简单的条件来过滤掉集合中添加 0
的部分:
// 用于跳过 0 值但保留键的替代 fold
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
或者,也可以进行聚合,但是您的 result
变量需要更改为 Map<String, MutableSet<Long>>
:
val result: Map<String, MutableSet<Long>> = // ...
.aggregate { _, accumulator, element, first ->
(if (first) mutableSetOf<Long>() else accumulator!!).also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
英文:
While the other answer(s) might be easier to grasp, they build immediate lists and maps in between, that are basically discarded right after the next operation. The following tries to omit that using splitToSequence
(Sequences) and groupingBy
(see Grouping bottom part):
val result: Map<String, Set<Long>> = input.splitToSequence(',')
.map { it.split('|', limit = 2) }
.groupingBy { it[0] }
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
it.add(element[1].toLong()))
}
}
You can of course also filter out the addition of 0
in the set with a simple condition in the fold
-step:
// alternative fold skipping 0-values, but keeping keys
.fold({ _, _ -> mutableSetOf<Long>() }) { _, accumulator, element ->
accumulator.also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
Alternatively also aggregating might be ok, but then your result
-variable needs to change to Map<String, MutableSet<Long>>
:
val result: Map<String, MutableSet<Long>> = // ...
.aggregate { _, accumulator, element, first ->
(if (first) mutableSetOf<Long>() else accumulator!!).also {
val value = element[1].toLong()
if (value != 0L)
it.add(value)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论