2

I'm doing a bit of Leetcode, and I'm facing this issue: Group Anagrams, I have a Python background and I can do the following:

res = defaultdic(list)

count = [0] * 26

res[tuple(count)].append(s)

as we can see we can set the tupled array as the key for the dictionary, I want to do the same thing in Kotlin, however, when creating this in Kotlin, I get a different object every time when adding this logic in a for loop.

fun groupAnagrams(strs: Array<String>): List<List<String>> {
    val hashMap = hashMapOf<IntArray, ArrayList<String>>()

    for (word in strs) {
        val array = IntArray(26) { 0 }

        for (char in word) {
            val charInt = char - 'a'

            array[charInt] += 1
        }

        if (hashMap.containsKey(array)) {
            hashMap[array]!!.add(word)
        } else {
            hashMap[array] = ArrayList<String>().apply { add(word) }
        }
    }

    return hashMap.values.toList()
}

Is this something can be done in Kotlin?

1
  • Alternatively to the provided solution one could also use the contentHashCode of an array like this: hashMap[array.contentHashCode()] This eliminated the need to use a List. Commented Feb 15, 2023 at 22:35

2 Answers 2

7

Equality for IntArray is checked based on its reference. You can use a List here in place of IntArray. Two Lists are equal if they contain the same elements.

Modified code will be like this:

fun groupAnagrams(strs: Array<String>): List<List<String>> {
    val hashMap = hashMapOf<List<Int>, ArrayList<String>>()

    for (word in strs) {
        val array = List(26) { 0 }.toMutableList()

        for (char in word) {
            val charInt = char - 'a'
            array[charInt] += 1
        }

        if (hashMap.containsKey(array)) {
            hashMap[array]!!.add(word)
        } else {
            hashMap[array] = ArrayList<String>().apply { add(word) }
        }
    }

    return hashMap.values.toList()
}
Sign up to request clarification or add additional context in comments.

3 Comments

May also be worth renaming array since it's no longer an array :-) And worth pointing out that if you use mutable objects as map keys, you must ensure that they can't change thereafter; if they do, then the map can behave inconsistently, being unable to find keys or even throwing exceptions.
Are you referring to this code in your second point? I didn't get that. Where are mutable keys here?
My second was a general point that people should be aware of, not a problem with anything in your answer. (Feel free to add it to your answer if you want.)
0

Avoiding the problem you run into (equality of arrays) by using String keys:

fun groupAnagramsWithHashing(strs: Array<String>): List<List<String>> {
    val map = hashMapOf<String, MutableList<String>>()

    MessageDigest.getInstance("SHA-1").also { sha ->
        for (word in strs) {
            word.toByteArray().sorted().forEach { sha.update(it) }

            val key = sha.digest().joinToString()
            map.computeIfAbsent(key) { mutableListOf() }.add(word)
        }
    }
    return map.values.toList()
}

fun main() {
    val input = arrayOf("eat", "tea", "tan", "ate", "nat", "bat")
    groupAnagramsWithHashing(input).also { println(it) }
    // [[eat, tea, ate], [bat], [tan, nat]]
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.