UP | HOME

排序

Table of Contents

元素的顺序是某些集合类型的一个重要方面

  例如,如果拥有相同元素的两个列表的元素顺序不同,那么这两个列表也不相等

在 Kotlin 中,可以通过多种方式定义对象的顺序:

大多数内置类型是可比较的:

如需为用户定义的类型定义一个自然顺序,可以让这个类型继承 Comparable。 这需要实现 compareTo() 函数。 compareTo() 必须将另一个具有相同类型的对象作为参数并返回一个整数值来显示哪个对象更大:

下面是一个类,可用于排序由主版本号和次版本号两部分组成的版本:

class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        } else if (this.minor != other.minor) {
            return this.minor - other.minor
        } else return 0
    }
}

fun main() {    
    println(Version(1, 2) > Version(1, 3))
    println(Version(2, 0) > Version(1, 5))
}

自定义 顺序可以按自己喜欢的方式对任何类型的实例进行排序。 特别是,可以为不可比较类型定义顺序,或者为可比较类型定义非自然顺序。 如需为类型定义自定义顺序,可以为其创建一个 Comparator。 Comparator 包含 compare() 函数:它接受一个类的两个实例并返回它们之间比较的整数结果。 如上所述,对结果的解释与 compareTo() 的结果相同

fun main() {
//sampleStart
    val lengthComparator = Comparator { str1: String, str2: String -> str1.length - str2.length }
    println(listOf("aaa", "bb", "c").sortedWith(lengthComparator))
//sampleEnd
}
  有了 lengthComparator,可以按照字符串的长度而不是默认的字典顺序来排列字符串

定义一个 Comparator 的一种比较简短的方式是标准库中的 compareBy() 函数。 compareBy() 接受一个 lambda 表达式,该表达式从一个实例产生一个 Comparable 值,并将自定义顺序定义为生成值的自然顺序。 使用 compareBy(),上面示例中的长度比较器如下所示

fun main() {
//sampleStart    
println(listOf("aaa", "bb", "c").sortedWith(compareBy { it.length }))
//sampleEnd
}

Kotlin 集合包提供了用于按照自然顺序、自定义顺序甚至随机顺序对集合排序的函数

自然顺序

基本的函数 sorted()sortedDescending() 返回集合的元素,这些元素按照其 自然 顺序 升序降序 排序。 这些函数适用于 Comparable 元素的集合:

fun main() {
//sampleStart
    val numbers = listOf("one", "two", "three", "four")

    println("Sorted ascending: ${numbers.sorted()}")
    println("Sorted descending: ${numbers.sortedDescending()}")
//sampleEnd
}

自定义顺序

为了按照自定义顺序排序或者对不可比较对象排序,可以使用函数 sortedBy()sortedByDescending() 。 它们接受一个将集合 元素 映射Comparable 值的选择器函数,并以该值的自然顺序对集合排序:

fun main() {
//sampleStart
    val numbers = listOf("one", "two", "three", "four")

    val sortedNumbers = numbers.sortedBy { it.length }
    println("Sorted by length ascending: $sortedNumbers")
    val sortedByLast = numbers.sortedByDescending { it.last() }
    println("Sorted by the last letter descending: $sortedByLast")
//sampleEnd
}

如需为集合排序定义自定义顺序,可以提供自己的 Comparator。 为此,调用传入 Comparator 的 sortedWith() 函数。 使用此函数,按照字符串长度排序如下所示:

fun main() {
//sampleStart
    val numbers = listOf("one", "two", "three", "four")
    println("Sorted by length ascending: ${numbers.sortedWith(compareBy { it.length })}")
//sampleEnd
}

倒序

可以使用 reversed() 函数以相反的 索引 顺序检索集合:

fun main() {
//sampleStart
    val numbers = listOf("one", "two", "three", "four")
    println(numbers.reversed())
//sampleEnd
}
reversed() 返回带有元素副本的新集合。 因此,如果之后改变了原始集合,这并不会影响先前获得的 reversed() 的结果

另一个反向函数 asReversed() 返回相同集合实例的一个反向视图,因此,如果原始列表不会发生变化,那么它会比 reversed() 更轻量,更合适:

fun main() {
//sampleStart
    val numbers = listOf("one", "two", "three", "four")
    val reversedNumbers = numbers.asReversed()
    println(reversedNumbers)
//sampleEnd
}

如果原始列表是 可变的 ,那么其所有 更改 都会 反映 在其 反向视图 中,反之亦然

fun main() {
//sampleStart
    val numbers = mutableListOf("one", "two", "three", "four")
    val reversedNumbers = numbers.asReversed()
    println(reversedNumbers)
    numbers.add("five")
    println(reversedNumbers)
//sampleEnd
}

如果列表的可变性未知或者源根本不是一个列表,那么 reversed() 更合适,因为其结果是一个未来不会更改的副本

随机顺序

shuffled() 函数返回一个包含了以随机顺序排序的集合元素的新的 List。 可以不带参数或者使用 Random 对象来调用它:

fun main() {
//sampleStart
     val numbers = listOf("one", "two", "three", "four")
     println(numbers.shuffled())
//sampleEnd
}
Next:聚合 Previous:单个 Home:集合