我正在编写一个迭代一个集合的函数,并找到其中最常见的项目。
以下是我到目前为止获取值并添加它们在集合中出现的次数。我将值作为键放在地图中,并将其显示为其值。
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接收器上使用。
答案 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
}