【问题标题】:sortedBy parameter as a variablesortedBy 参数作为变量
【发布时间】:2018-04-23 16:39:55
【问题描述】:

我有一个方法需要以多种可能的方式对集合进行排序。我不想多次调用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)
}

有什么想法吗?

【问题讨论】:

    标签: sorting lambda collections kotlin


    【解决方案1】:

    问题在于这两个 lambda 的类型非常不同,所以变量comparator 的类型被简单地推断为Any,这是第一个常见的超类型。如果您需要能够为它分配任一 lambda,则此变量没有其他类型(Any? 除外)。

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


    但是,有一个解决方案。您可以在不同的 when 分支中创建 Comparator&lt;Person&gt; 实例,而不是使用 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)
    

    【讨论】:

    • 谢谢!那工作得很好。我之前不知道compareBy
    【解决方案2】:

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

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

    【讨论】:

    • 重点是让变量sort能够容纳Person::agePerson::name等,不同类型。这就是为什么我的示例有 when 场景(实际场景比仅按一个字段排序,硬编码更复杂)。这种解决方案在这种情况下不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 2014-12-28
    • 2013-12-22
    相关资源
    最近更新 更多