Kotlin:找到集合中最常见的元素

时间:2018-01-30 21:26:37

标签: hashmap kotlin

我正在编写一个迭代一个集合的函数,并找到其中最常见的项目。

以下是我到目前为止获取值并添加它们在集合中出现的次数。我将值作为键放在地图中,并将其显示为其值。

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

如果密钥已存在,我无法找到将值加1的方法。

我试过这样做:

newMap[item] +=1

但是我得到一个关于plusAssign(1)的错误,不允许在Nullable接收器上使用。

4 个答案:

答案 0 :(得分:9)

正如您已经注意到的,错误与可空性处理有关。我提出了一种更具功能性的方法,没有明确的循环,只是简单的分组:

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

结果是一个Map,其中input的元素作为其键,元素的出现次数为相应的值。

现在,您可以找到maxBy最常见的元素:

numbersByElement.maxBy { it.value }?.key // gives an Int?

答案 1 :(得分:7)

Map.get会返回Int?,即如果找不到任何项目,则会返回null。您可以使用elvis运算符来处理:

val newMap = mutableMapOf<Int, Int>()

for (item in input) {
    newMap[item] = (newMap[item] ?: 0) + 1
}

另一种方法是使用Java 8的Map.merge

newMap.merge(item, 1) { i, j -> i + j }
// or the equivalent
newMap.merge(item, 1, Int::plus)

如果密钥不存在,这将把1放在地图中,否则将lambda应用于旧值和新值,在我们的例子中将旧值添加到新值并存储结果在钥匙下。

答案 2 :(得分:0)

我认为以下应该可行。

val arr = listOf(1,2,3,4,5,6,7,3,4,2,3,1,4,5,2,7,8,2,3,3,3,3)
val maxOccurring = arr.groupBy { it }.mapValues { it.value.size }.maxBy { it.value }?.key

在这种情况下返回3。

答案 3 :(得分:0)

带有Kotlin-1.4预览的优雅nullsafe解决方案

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