Home > Enterprise >  Adding to list from hashmap key kotlin
Adding to list from hashmap key kotlin

Time:05-25

I'm practicing leetcode problems to perfect my kotlin syntax and am wondering why this code doesn't work. My question specifically is why doesn't my courses hashmap populate with this code.

Prerequisites is an array in this form [[0,1][0,3][4,5][6,7]] and if I print my variables for pre and post they print what I expect

But I'm trying to turn courses into an adjacency matrix like this {0: [1,3], 4: [5], 6: [7]} and instead it just prints an empty set every time

class Solution {
    fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
        val courses = HashMap<Int, MutableList<Int>>().withDefault{ mutableListOf<Int>() }
        
        for ((pre, post) in prerequisites){
            courses[pre]?.add(post)
        }
        print(courses)
      
        return false
    }
}
stdout: {}

CodePudding user response:

[] does not give you the default value

From the docs of withDefault:

This implicit default value is used when the original map doesn't contain a value for the key specified and a value is obtained with Map.getValue function

If you want to get the default value, you need to use getValue instead of the index operator.

Using the index operator, you would just get null and because of the the null-safe operator, the add operation would not even be executed.

If you take a look at the relevant source code, you can see that the funxtionality get is not changed when using .withDefault but only getOrImplicitDefault returns the default value.

Getting the default does not set anything

Furthermore, when accessing courses.getValue(pre) in the loop, the Map will be empty. Because of the withDefault, it will return a MutableList where you can add elements but getting such a list and adding elements to it will not add the list to the Map. Reading and accessing an element does not insert it.

Simple solution

If you want to make sure the element is present in the Map, you can use courses[pre]=course.getValue(pre) before reading courses[pre]?:

class Solution {
    fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
        val courses = HashMap<Int, MutableList<Int>>().withDefault{ mutableListOf<Int>() }
        
        for ((pre, post) in prerequisites){
            courses[pre] = courses.getValue(pre)
            courses[pre]?.add(post)
        }
        print(courses)
      
        return false
    }
} 

If the entry is set already, it will be set to itself (no change) and if it isn't set, it will be set to the default value (empty list).

CodePudding user response:

dan1st's answer covers it - your default list is just returned, not put and returned, so it's not part of the map - but here's a different take to get that functionality:

val courses = HashMap<Int, MutableList<Int>>().run {
        withDefault{ key ->
            mutableListOf<Int>().also { put(key, it) }
        }
    }

So basically using the withDefault wrapper, using run so the map is this in the default value function, so you can add your list to the map before returning it. Then when you call courses.getValue(69) you'll get back a list that's already been inserted into the map

If you like, there's also a function that'll do this grouping for you, groupBy

val nums = arrayOf(
        intArrayOf(0,1),
        intArrayOf(0,3),
        intArrayOf(4,5),
        intArrayOf(6,7)
    )

val groups = nums.groupBy(keySelector = { it[0] }, valueTransform = { it[1] })
println(groups)

>> {0=[1, 3], 4=[5], 6=[7]}
  • Related