Kotlin / Java functional and immutable way of collecting a map on a map

I am currently reading a file through the Java API and adding items to the map through the foreach method which forces me to use mutablemap. Is there a way to collect items without mutablemap? I know there is a collection method, but I couldn't get it to work.

current way:

    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)))
                    }

      

EDIT:

My goal is to combine ternary objects based on the first value of the triple. Thus, the scenario will consist of two triple objects (1, 2, 5.5) and (1,3, 5.5). The first triple value is the user ID, the second is the article ID, and the third is the article rating. after the merge there will be one entry in the map containing the first key = user id, the first value of the triple, and the value will be a map containing the articles the user has rated.

I am currently working on how I want it to work, but I was curious if there is a more functional way of solving this issue.

+3


source to share


2 answers


You can do it:

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() }))

      



The compiler didn't seem to be able to infer the types for toMap

, so I added the hint type there.

Note that Kotlin does not have an immutable implementation Map

. By default, what is returned mapOf

is java.util.LinkedhashMap

which is mutable. It's just that the interface Map

does not expose mutation methods (e.g. put

, putAll

). And you can freely assign MutableMap<Int, MutableMap<Int, Double>>

Map<Int, Map<Int, Double>>

, which is also what I do here with the type annotation on result

, I force the static type to be immutable Map

.

+2


source


I'm not comfortable with Kotlin

, but it seems that you have to use a simple: Collectors.collectingAndThen

. Something like:

  System.out.println(Stream.of(1, 2, 3, 1)
             .collect(Collectors.collectingAndThen(
                  Collectors.groupingBy(Function.identity(), Collectors.counting()),
                       Collections::unmodifiableMap)));

      



The idea is that you build onto a mutable map and then drag it to ImmutableMap.

If, by the way, you have guava

a classpath in it, it has build collectors that are going to ImmutableMap

.

+2


source







All Articles