在 Kotlin 中将列表<对<K、集合<V>>>转换为地图<K,集合<V>>



有人知道如何转换List

在Java中,我会使用如下格式:

.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (c1, c2) -> {
      List result = new ArrayList<>();
      result.addAll(c1);
      result.addAll(c2);
      return result;
})

Kotlin是否有类似的设备,或者更好的?如有任何建议,不胜感激。

供您参考,Kotlin有一个toMap函数,在您不需要合并重复键的值的情况下。

然而,如果你想合并,你将不得不使用稍微复杂一点的方法。假设您有一个这样的对列表:

val pairs = listOf(
    1 to listOf("1", "2", "3"),
    1 to listOf("4"),
    2 to listOf("1", "2", "3"),
    3 to listOf("1", "2", "3"),
    3 to listOf("4", "5", "6"),
)

你可以这样使用groupBy和mapValues:

val map = pairs.groupBy({ it.first }, { it.second })
               .mapValues { (k, v) -> v.flatten() }

groupBy将创建Map<Int, List<List<String>>>,因此每个键将映射到与其对应的所有值的列表。然后mapValues将每个列表的列表扁平化,使其成为单个列表。

注意,这会创建一个中间映射,与所提供的Java相比,在性能敏感的代码中可能不是很有效。如果您需要效率,您可以使用groupingBy来获得更惰性的分组,并按照您的意愿进行聚合。例如:

val map = pairs.groupingBy { it.first }
               .fold(emptyList<String>()) { acc, v -> acc + v.second }

很好,但是在合并时会创建中间列表。或:

val map = pairs.groupingBy { it.first }.fold(
    initialValueSelector = { _, _ -> mutableListOf<String>() },
    operation = { _, acc, v -> acc.addAll(v.second); acc }
)

为每个键创建一个列表,但稍微复杂一些。如果你想变得更疯狂,也可以使用其他变体:

val map = pairs.groupingBy { it.first }.aggregate { k, acc: List<String>?, v, _ ->
    if (acc == null) v.second else acc + v.second
}

(不可否认这有点拗口,并且仍然创建中间列表)

可以使用associate进行隐蔽。比如:

listOf(
    Pair(1, listOf("1", "2", "3")),
    Pair(2, listOf("1", "2", "3")),
    Pair(3, listOf("1", "2", "3"))
).associate { it.first to it.second }

结果是map:

{1=[1, 2, 3], 2=[1, 2, 3], 3=[1, 2, 3]}

如果只需要第一个元素作为值,则只需要修改映射到it.second.first()的值。

最新更新