sortedBy参数作为变量

时间:2018-04-23 16:39:55

标签: sorting lambda collections kotlin

我有一种方法需要以多种可能的方式对集合进行排序。我没有多次调用myCollection.sortedBy,而是希望将变量传递给sortedBy的lambda,然后我将该变量传递给一个变量单次拨打sortedBy。但是,我无法弄清楚lambda变量应具有的类型。请记住"排序字段"可能有不同的类型(但显然它们都是Comparable

这是我的问题的简化版本:

data class Person(val name: String, val age: Int)

enum class SortBy {
    NAME, AGE
}

fun main(args: Array<String>) {
    val people = listOf(Person("John", 30), Person("Mary", 20))
    val sort = SortBy.NAME

    val comparator = when (sort) {
        SortBy.NAME -> { p: Person -> p.name }
        SortBy.AGE -> { p: Person -> p.age }
    }

    // the line below won't compile
    people.sortedBy(comparator).forEach(::println)
}

有什么想法吗?

2 个答案:

答案 0 :(得分:7)

问题是两个lambda具有非常不同的类型,因此变量comparator的类型简单地推断为Any,这是第一个常见的超类型。如果你需要能够将lambdas中的任何一个赋值给它,那么这个变量就没有其他类型(Any?除外)。

然后,根据您最终得到的结果((Person) -> Int(Person) -> String),sortedBy方法必须以某种方式推断其类型参数,这也是不可能的。处理这两种情况。

但是,有一个解决方案。您可以在不同的Comparator<Person>分支中创建when个实例,而不是通过compareBy函数将Person实例与之比较的特定类型包装起来:

val comparator: Comparator<Person> = when (sort) {
    SortBy.NAME -> compareBy { it.name }
    SortBy.AGE -> compareBy { it.age }
}

然后使用sortedWith方法,该方法采用Comparator而不是选择器lambda:

people.sortedWith(comparator).forEach(::println)

答案 1 :(得分:0)

您可以简单地使用属性引用

val people = listOf(Person("John", 30), Person("Mary", 20))
val sort = Person::age
people.sortedBy(sort).forEach(::println)