1. 概述
Kotlin 提供了功能强大且简洁的集合库,其中包含大量实用方法,能高效处理集合数据。
本文将重点解析两个常用于聚合统计的方法:eachCount()
和 eachCountTo()
。它们在构建频次统计时非常有用,但使用场景略有不同,稍不注意容易踩坑 ❌。
2. eachCount()
✅ 核心作用:对分组后的元素进行计数,返回一个不可变的 Map
,键为分组 key,值为该组元素的数量。
- 该方法依赖于
Grouping
接口,通常通过groupingBy { }
创建。 - 常用于生成频次映射(frequency map),比如统计每个前缀出现次数。
示例代码
val flights = listOf("EK060", "EK531", "LH7", "LH1030", "DL47", "AI120")
val flightCount = flights.groupingBy { it.take(2) }.eachCount()
val expectedMap = mapOf("EK" to 2, "LH" to 2, "DL" to 1, "AI" to 1)
assertEquals(expectedMap, flightCount)
📌 解读:
it.take(2)
提取航班号前两位作为航空公司代号(如 EK、LH)。groupingBy { }
构建分组结构。eachCount()
自动完成计数并返回Map<String, Int>
。
对比传统写法
你也可以用 groupBy()
+ mapValues()
实现相同逻辑:
val flightCount = flights.groupBy { it.take(2) }.mapValues { it.value.size }
⚠️ 缺点:
- 多次遍历:
groupBy()
先创建完整子列表,内存开销更大。 - 不够高效:
eachCount()
内部是增量计数,仅遍历一次,性能更优。
因此,在只需要计数而非具体元素列表时,优先使用 eachCount()
✅。
3. eachCountTo()
✅ 核心作用:将分组计数结果累加到一个已有的可变 Map 中,适合需要持续累积统计的场景。
- 方法签名:
eachCountTo(destination: MutableMap<K, Int>)
- 不创建新 Map,而是复用传入的
destination
,原地更新计数。 - 非常适合流式处理、分批统计或缓存聚合结果。
示例代码
val flights = listOf("EK060", "EK531", "LH7", "LH1030", "DL47", "AI120")
val flightCount = mutableMapOf<String, Int>().apply {
flights.groupingBy { it.take(2) }.eachCountTo(this)
}
val expectedMap = mutableMapOf("EK" to 2, "LH" to 2, "DL" to 1, "AI" to 1)
assertEquals(expectedMap, flightCount)
// 新增航班数据
val moreFlights = listOf("EK061", "AI435")
moreFlights.groupingBy { it.take(2) }.eachCountTo(flightCount)
val expectedMapAfterMoreFlights = mutableMapOf("EK" to 3, "LH" to 2, "DL" to 1, "AI" to 2)
assertEquals(expectedMapAfterMoreFlights, flightCount)
📌 关键点:
- 第一次调用
eachCountTo()
初始化计数。 - 后续新增数据时,直接复用同一个
flightCount
Map 继续累加。 - 最终 EK 从 2 变成 3,AI 从 1 变成 2,体现了“增量更新”的优势。
使用建议
场景 | 推荐方法 |
---|---|
一次性统计,无需后续修改 | eachCount() |
分批处理数据,需持续累加 | eachCountTo() ✅ |
性能敏感,避免中间对象创建 | eachCountTo() 更优 |
4. 总结
方法 | 返回类型 | 是否修改参数 | 典型用途 |
---|---|---|---|
eachCount() |
Map<K, Int> (不可变) |
❌ 否 | 单次聚合,快速生成频次表 |
eachCountTo() |
MutableMap<K, Int> (原地更新) |
✅ 是 | 多批次累加、内存敏感场景 |
📌 核心区别一句话总结:
eachCount()
是“从零生成”,而eachCountTo()
是“接着算”。
合理选择这两个方法,不仅能提升代码可读性,还能优化性能和内存使用。尤其在处理大规模数据流或实时统计时,eachCountTo()
的增量特性极具价值 ✅。
示例代码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-collections-6