Kotlin-在某些情况下使用新值类型按键对元素进行分组

时间:2018-08-21 14:58:01

标签: collections kotlin hashmap mapping flatmap

我试图找到一种使用Kotlin收集操作来做一些我要解释的逻辑的方法:

假设类型Classroom包含一个列表Student作为其中的一个字段,eg. classroom.getSudents()返回一个特定对象的列表。

现在,我有一个混合的Student列表,需要按其一个字段分组,例如 major ,结果映射的值为Classroom

所以我需要将List<Student>转换为Map<Student.major, Classroom>

在某些情况下,例如主要,例如对于所有major == chemistry,我还需要按另一个条件(例如名字)分组,因此键化学的major_firstname

这是一个例子,我有一个Student(major, firstname)的列表:

[
    Student("chemistry", "rafael"), 
    Student("physics", "adam"),
    Student("chemistry", "michael"),
    Student("math", "jack"),
    Student("chemistry", "rafael"),
    Student("biology", "kevin")
]

我需要的结果是:

{
    "math" -> Classroom(Student("math", "jack")),
    "physics" -> Classroom(Student("physics", "adam")),
    "chemistry_michael" -> Classroom(Student("chemistry", "michael")),
    "chemistry_rafael" -> Classroom(Student("chemistry", "rafael"), Student("chemistry", "rafael")),
    "biology" -> Classroom(Student("biology", "kevin"))
}

我尝试过groupByflatMapToassociateBy,但据我了解,所有这些都不是在一定条件下组合的。

2 个答案:

答案 0 :(得分:0)

实际上是您需要的那些方法的混合。还有其他方法可以实现,但是这里有一个使用groupByflatMap的示例:

val result = students.groupBy { it.major }
    .flatMap { (key, values) -> when (key) {
        "chemistry" -> values.map { it.firstname }
                             .distinct()
                             .map { firstname -> "chemistry_$firstname" to ClassRoom(values.filter { it.firstname == firstname }) }
        else -> listOf(key to ClassRoom(values))
    }
}.toMap()

假定以下数据类:

data class Student(val major: String, val firstname: String)
data class ClassRoom(val students : List<Student>)

如果您还想要一张按专业划分所有学生的地图,则满足以下条件:

val studentsPerMajor = students.groupBy { it.major }
                               .map { (major, values) -> major to ClassRoom(values) }

如果您想继续使用该地图,而不是重新计算源代码中的所有内容,例如然后以下内容将根据studentsPerMajor返回您想要的地图:

val result = studentsPerMajor.flatMap { (key, classroom) -> when (key) {
        "chemistry" -> classroom.students.map { it.firstname }
                                         .distinct()
                                         .map { firstname -> "chemistry_$firstname" to ClassRoom(classroom.students.filter { it.firstname == firstname }) }
        else -> listOf(key to classroom)
    }
}.toMap()

答案 1 :(得分:0)

我将尝试回答第一部分,因为Roland发布了第二部分的答案(尽管我没有尝试过)。
假设您的课程是:

class Student(val major: String, val firstName: String)

class Classroom(val studentList: MutableList<Student>) {
    fun getStudents(): MutableList<Student> {
        return studentList
    }
}

并使用类似

的初始化
val list = mutableListOf<Student>(
        Student("chemistry", "rafael"),
        Student("physics", "adam"),
        Student("chemistry", "michael"),
        Student("math", "jack"),
        Student("chemistry", "rafael"),
        Student("biology", "kevin"))

val classroom = Classroom(list)
val allStudents = classroom.getStudents()

您可以有一个结果列表:

val finalList: MutableList<Pair<String, Classroom>> = mutableListOf()

allStudents.map { it.major }.distinctBy { it }.forEach { major ->
    finalList.add(major to Classroom(allStudents.filter { it.major == major }.toMutableList()))
}

因此请输入以下代码:

finalList.forEach {
    println(it.first + "->")
    it.second.getStudents().forEach { println("    " + it.major + ", " + it.firstName) }
}

这将被打印:

chemistry->
    chemistry, rafael
    chemistry, michael
    chemistry, rafael
physics->
    physics, adam
math->
    math, jack
biology->
    biology, kevin