Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Find most common element in collection

Tags:

hashmap

kotlin

I am writing a function that iterates through a collection and finds the most common items occurring in it.

Here is what I have so far to get the values and add the number of times they appear in the collection. I'm putting the value into a map as a key and the number of times it appears as its value.

fun mostCommon(input: Collection<Int>): Set<Int> {
    var newMap: MutableMap<Int, Int> = HashMap()
    for (item in input) {
        if (newMap.containsKey(item)) {
            //TODO: add 1 to value if key is found
        } else {
            newMap.put(item, 1)
        }
    }
    return emptySet()
}

I am having trouble finding a way to add 1 to its value if the key already exists.

I tried doing this:

newMap[item] +=1

But I get an error about plusAssign(1) not being allowed on Nullable receiver.

like image 769
cela Avatar asked Jan 30 '18 21:01

cela


2 Answers

As you already noticed, the error was related to nullability-handling. I'd suggest a more functional approach without explicit looping but simple grouping:

val numbersByElement = input.groupingBy { it }.eachCount()
//gives something like this {1=3, 2=5, 3=4, 5=2, 4=1}

The result is a Map with the elements from input as its keys and the number of occurrences of the elements as the corresponding values.

You can now find the most common element with maxBy:

numbersByElement.maxBy { it.value }?.key // gives an Int?
like image 71
s1m0nw1 Avatar answered Nov 01 '22 11:11

s1m0nw1


elegant nullsafe solution with Kotlin-1.4 preview

@Test
fun testFindOutMostCommonStringInList() {
    val mostCommon = findMostCommonInList(listOf("Foo", "Boo", null, "Foo", "Hello"))
    assertEquals("Foo", mostCommon)
}

@Test
fun testFindOutMostCommonIntInList() {
    val mostCommon = findMostCommonInList(listOf(1, 2, null, 3, 4, 5, 1))
    assertEquals(1, mostCommon)
}

private fun <T>findMostCommonInList(list : List<T>) : T? {
    return list
        .groupBy { it }
        .maxByOrNull { it.value.size }
        ?.key
}
like image 40
Minki Avatar answered Nov 01 '22 11:11

Minki