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


原始标题:Difference Between eachCount() and eachCountTo() Methods in Kotlin