1. 概述
在编程中,Map
是一种非常常用的数据结构,用于保存键值对(Key-Value Pair)。在 Kotlin 中,我们经常需要处理 Map 的各种操作,其中一项常见的需求是:如何从 Map 中找出“最大”的一个条目?
这个问题看似简单,但“最大”这个概念在不同业务场景下可能有不同的定义。本篇文章将围绕这个主题,通过两个典型场景来演示如何使用 Kotlin 的集合操作函数,优雅地解决这个问题。
我们会使用 Kotlin 提供的 maxBy()
、maxWith()
以及 maxOf()
等函数进行实现,并通过单元测试验证结果的正确性。
2. 问题定义
一个 Map 条目(Entry)由键(Key)和值(Value)组成。因此,所谓“最大”条目可以根据不同的标准来定义。
我们以如下 Map<String, String>
为例:
val skillMap = mapOf(
"Kai" to "Kotlin, typescript, Javascript, C, C++",
"Saajan" to "Java, C, Python, Ruby, Shell, Go",
"Eric" to "Kotlin, Java, C, Python, Ruby, Php, Shell, Rust",
"Kevin" to "Java, Scala, Go, Ruby",
"Venus" to "Beauty!"
)
在这个 Map 中,键是人名,值是技能列表(以逗号分隔的字符串)。
根据不同的业务需求,“最大”可以有如下几种常见定义:
✅ 基于值的比较:技能最多的条目
✅ 基于键的比较:名字最长的条目
接下来我们将分别讨论这两种情况,并演示如何用 Kotlin 实现。
3. 查找技能最多的条目
我们首先考虑“技能最多”的情况。技能数量由值中逗号分隔的字符串长度决定。
Kotlin 提供了非常简洁的集合操作函数,我们可以使用 maxBy()
方法来实现:
val result = skillMap.maxBy { (_, skills) -> skills.split(", ").size }
assertEquals("Eric" to "Kotlin, Java, C, Python, Ruby, Php, Shell, Rust", result.toPair())
💡 说明:
maxBy()
接收一个 lambda 表达式,该表达式用于定义每个条目的比较值。- 我们只关心值(skills),因此使用
_
忽略键。 split(", ").size
计算技能数量。
另一种实现方式是使用 maxWith()
,传入一个自定义的 Comparator
:
val result = skillMap.maxWith { e1, e2 ->
e1.value.split(", ").size.compareTo(e2.value.split(", ").size)
}
assertEquals("Eric" to "Kotlin, Java, C, Python, Ruby, Php, Shell, Rust", result.toPair())
4. 查找名字最长的条目
接下来我们考虑“名字最长”的情况。这属于基于键的比较。
我们依然可以使用 maxBy()
,但这次比较的是键的长度:
val result1 = skillMap.maxBy { (name, _) -> name.length }
assertEquals("Saajan" to "Java, C, Python, Ruby, Shell, Go", result1.toPair())
同样,也可以使用 maxWith()
:
val result2 = skillMap.maxWith { e1, e2 -> e1.key.length.compareTo(e2.key.length) }
assertEquals("Saajan" to "Java, C, Python, Ruby, Shell, Go", result2.toPair())
5. 关于 maxOf()
函数
除了 maxBy()
和 maxWith()
,Kotlin 还提供了 maxOf()
函数,但它的行为略有不同。
⚠️ 注意:maxOf()
返回的是 selector 函数计算出的最大值,而不是整个 Map.Entry。
举几个例子:
val result = skillMap.maxOf { (name, _) -> name }
assertEquals("Venus", result)
这里我们提取的是键,所以返回的是字典序最大的键 "Venus"
。
再来看一个提取字符的例子:
val result = skillMap.maxOf { (name, _) -> name[1] }
assertEquals('r', result)
这次我们提取的是每个键的第二个字符,返回的是最大字符 'r'
。
最后,我们也可以用 maxOf()
来提取技能数量的最大值:
val result = skillMap.maxOf { it.value.split(", ").size }
assertEquals(8, result)
✅ 总结:
maxBy()
和maxWith()
返回的是整个条目(Entry)maxOf()
返回的是 selector 函数计算出的最大值,而不是条目本身
6. 总结
本文介绍了如何在 Kotlin 中查找 Map 的最大条目。我们通过两个典型场景:
- ✅ 基于值(技能数量)查找最大条目
- ✅ 基于键(名字长度)查找最大条目
使用了如下函数:
maxBy()
:根据 selector 函数返回的值比较,返回最大条目maxWith()
:传入 Comparator 自定义比较逻辑maxOf()
:返回 selector 函数计算出的最大值,不是条目本身
这些函数都非常简洁,而且可读性强,是 Kotlin 集合操作中非常实用的工具。
如需查看完整示例代码,欢迎访问 GitHub 仓库。