Kotlin/Java 在地图中收集地图的实用且不可变的方式
Kotlin/Java functional and immutable way of collecting a map in a map
目前我正在通过 Java API 读取文件并通过 foreach 方法将项目添加到地图,这迫使我使用可变地图。有没有办法在没有可变映射的情况下收集项目?我知道有一个方法 collect 但我无法让它工作。
当前方式:
val result = mutableMapOf<Int, MutableMap<Int, Double>>()
Files.lines(Paths.get(folderPath))
.map { line -> line.split(",") }
.map { items -> Triple(items[0].toInt(), items[1].toInt(), items[2].toDouble()) }
.forEach { (id, article, rating) ->
if (result.containsKey(id))
result[id]!!.put(article, rating)
else
result.put(id, mutableMapOf(Pair(article, rating)))
}
编辑:
我的目标是根据三元组的第一个值合并三元组对象。
因此,一个场景是两个三重对象(1、2、5.5)和(1,3、5.5)。三元组的第一个值是用户 ID,第二个是文章 ID,第三个是文章的评分。
合并后,映射中将有一个条目包含第一个键 = 用户 ID,三元组的第一个值,该值将是包含用户评价的文章的映射。
它目前正在按我希望的方式工作,但我很好奇是否有更实用的方法来解决这个问题。
我对 Kotlin
不太满意,但您似乎应该使用简单的:Collectors.collectingAndThen
。类似于:
System.out.println(Stream.of(1, 2, 3, 1)
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(Function.identity(), Collectors.counting()),
Collections::unmodifiableMap)));
我们的想法是将数据收集到一个可变映射中,然后将其包装到一个 ImmutableMap 中。
顺便说一下,如果您在 class 路径上有 guava
- 它具有收集到 ImmutableMap
.
的构建收集器
你可以这样做:
val result: Map<Int, Map<Int, Double>> = Files.lines(Paths.get(folderPath))
.map { it.split(",") }
.collect(groupingBy({ it[0].toInt() },
toMap<List<String>, Int, Double>({ it[1].toInt() }) { it[2].toDouble() }))
编译器似乎无法推断 toMap
的类型,因此我在此处添加了类型提示。
我要指出的是,Kotlin 没有不可变的 Map
实现。 mapOf
返回的默认值是 java.util.LinkedhashMap
, 是 可变的。只是 Map
接口没有公开变异方法(如 put
、putAll
)。你可以自由地将 MutableMap<Int, MutableMap<Int, Double>>
分配给 Map<Int, Map<Int, Double>>
,这也是我在这里使用 result
上的类型注释所做的,我强制静态类型是不可变的Map
.
目前我正在通过 Java API 读取文件并通过 foreach 方法将项目添加到地图,这迫使我使用可变地图。有没有办法在没有可变映射的情况下收集项目?我知道有一个方法 collect 但我无法让它工作。
当前方式:
val result = mutableMapOf<Int, MutableMap<Int, Double>>()
Files.lines(Paths.get(folderPath))
.map { line -> line.split(",") }
.map { items -> Triple(items[0].toInt(), items[1].toInt(), items[2].toDouble()) }
.forEach { (id, article, rating) ->
if (result.containsKey(id))
result[id]!!.put(article, rating)
else
result.put(id, mutableMapOf(Pair(article, rating)))
}
编辑:
我的目标是根据三元组的第一个值合并三元组对象。 因此,一个场景是两个三重对象(1、2、5.5)和(1,3、5.5)。三元组的第一个值是用户 ID,第二个是文章 ID,第三个是文章的评分。 合并后,映射中将有一个条目包含第一个键 = 用户 ID,三元组的第一个值,该值将是包含用户评价的文章的映射。
它目前正在按我希望的方式工作,但我很好奇是否有更实用的方法来解决这个问题。
我对 Kotlin
不太满意,但您似乎应该使用简单的:Collectors.collectingAndThen
。类似于:
System.out.println(Stream.of(1, 2, 3, 1)
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(Function.identity(), Collectors.counting()),
Collections::unmodifiableMap)));
我们的想法是将数据收集到一个可变映射中,然后将其包装到一个 ImmutableMap 中。
顺便说一下,如果您在 class 路径上有 guava
- 它具有收集到 ImmutableMap
.
你可以这样做:
val result: Map<Int, Map<Int, Double>> = Files.lines(Paths.get(folderPath))
.map { it.split(",") }
.collect(groupingBy({ it[0].toInt() },
toMap<List<String>, Int, Double>({ it[1].toInt() }) { it[2].toDouble() }))
编译器似乎无法推断 toMap
的类型,因此我在此处添加了类型提示。
我要指出的是,Kotlin 没有不可变的 Map
实现。 mapOf
返回的默认值是 java.util.LinkedhashMap
, 是 可变的。只是 Map
接口没有公开变异方法(如 put
、putAll
)。你可以自由地将 MutableMap<Int, MutableMap<Int, Double>>
分配给 Map<Int, Map<Int, Double>>
,这也是我在这里使用 result
上的类型注释所做的,我强制静态类型是不可变的Map
.