ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
### 根据学生性别进行分组:groupBy 有时候我们需要对列表中的元素进行分组。以这个人列表为例,我们可能需要按照元素的不同特征来对列表进行分组(比如按照性别、分数、年龄等特征进行分组),分组之后的集合是一个Map。如果我们用传统的思路来实现这一操作的话,我们或许会这么去做(比如要按照性别进行分组): ``` fun groupBySex (students: List<Student>): Map<String, List<Student>> { val mStudents = ArrayList<Student>() // 定义男学生列表 var fStudents = ArrayList<Student>() // 定义女学生列表 //遍历学生列表 for (student in students) { if(student.sex == "m"){ mStudents.add(student) } else if(student.sex == "f") { fStudents.add(student) } } return mapOf("m" to mStudents, "f" to fStudents) } ``` 上面是传统的分组的代码,可以看到比较烦琐,还要定义许多中间变量,且容易出错。 好在Kotlin给我们提供了一个groupBy方法。那么如果要对人列表中的元素按照性别进行分组的话,我们就可以这样去做(紧接着filter函数章节的person数据类): ~~~ val mPersonsMap = persons.groupBy { it.sex } println(mPersonsMap) ~~~ 输出结果: ``` {m=[PersonData(name=Jilen, age=30, sex=m, score=85), PersonData(name=Shaw, age=18, sex=m, score=90), PersonData(name=Jack, age=30, sex=m, score=70)], f=[PersonData(name=Yison, age=40, sex=f, score=59), PersonData(name=Lisa, age=25, sex=f, score=88), PersonData(name=Pan, age=36, sex=f, score=55)]} ``` 可以看到,使用groupBy方法很容易就能就得到我们想要的结果。该数据结构的类型为`Map<String, List<Person>>`,其中有两个分组,一个是性别男对应的分组,一个是性别女对应的分组。 我们再来看另外一个例子,如何使用成员引用把字符串按照首字母分组: ``` fun main(args: Array<String>) { val list = listOf("a", "ab", "b") println(list.groupBy(String::first))//{a=[a, ab], b=[b]} } ``` >[info]注意,这里first 并不是String 类的成员,而是一个扩展。然而,可以把它当作成员引用访问。 #### groupBy源码 ~~~ public inline fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>> { return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector) } ~~~ ~~~ public inline fun <T, K, M : MutableMap<in K, MutableList<T>>> Iterable<T>.groupByTo(destination: M, keySelector: (T) -> K): M { for (element in this) { val key = keySelector(element) val list = destination.getOrPut(key) { ArrayList<T>() } list.add(element) } return destination } ~~~