Kotlin 集合 排序详解
前言
本篇文章,我们开始学习Kotlin中集合的排序操作
实际使用中,我们针对集合对象的排序属于高频操作了。
那么Kotlin是如何给我们提供集合的排序呢?排序是有别于Group分组的。
关于分组已经有相关的文档进行介绍了。
在添加集合时,我们默认不设置任何排序属性。集合是按照默认顺序进行添加的。
也就是说,我们怎么添加的。在集合中的顺序就是怎么样的。
我们排序,都是针对集合数据已经有值的情况下。重新调整集合里面的元素排放位置。
引读
Kotlin 集合 基本介绍 - Z同学 (zinyan.com)
Kotlin 集合 转换,过滤和检测 - Z同学 (zinyan.com)
Kotlin 集合 plus,minus和分组group详解 - Z同学 (zinyan.com)
Kotlin 集合 查询,检测,截取等方法介绍 - Z同学 (zinyan.com)
自然排序
kotlin 已经实现了的排序方式,我们只需要调用sorted或者sortedDescending 就能快捷实现。
元素从大到小和从小到大的排序。
sorted() 从小到大排序
kotlin给集合对象实现了一个sorted() 函数,实现了默认的自然排序效果。
也就是按照数值的从小到大进行排序。
如果集合对象是int型等数值,就会按照:0至1的顺序进行排序
如果集合对象是Char或者String :就会按照字符的字典顺序进行排序,也就是a,b,c,d... 等
示例:
fun main(string: Array<String>) {
//int 型
val intT = listOf(1, 2, 3, 0, 23, 54, 222, 9, 5)
println("实际结果:$intT")
println("排序结果:${intT.sorted()}")
//字符串
var test = listOf("A", "c", "b", "Y", "f", "x", "X")
println("实际结果:$test")
println("排序结果:${test.sorted()}")
//float
val floatT = listOf(0.1, 2.4, 1.0, 2.3, 4.5, 1.3)
println("实际结果:$floatT")
println("排序结果:${floatT.sorted()}")
}
//输出
实际结果:[1, 2, 3, 0, 23, 54, 222, 9, 5]
排序结果:[0, 1, 2, 3, 5, 9, 23, 54, 222]
实际结果:[A, c, b, Y, f, x, X]
排序结果:[A, X, Y, b, c, f, x]
实际结果:[0.1, 2.4, 1.0, 2.3, 4.5, 1.3]
排序结果:[0.1, 1.0, 1.3, 2.3, 2.4, 4.5]
这种是按照元素值的自动顺序进行升序排序。那么我们如果需要降序呢?
sortedDescending() 从大到小进行排序
排序要求是一样的,只是顺序进行了调整实现了从大到小的排序。
示例:
fun main(string: Array<String>) {
//int 型
val intT = listOf(1, 2, 3, 0, 23, 54, 222, 9, 5)
println("实际结果:$intT")
println("排序结果:${intT.sortedDescending()}")
}
//输出
实际结果:[1, 2, 3, 0, 23, 54, 222, 9, 5]
排序结果:[222, 54, 23, 9, 5, 3, 2, 1, 0]
上面的排序方式有几个限制。
不支持自定义元素的排序,不支持多种参数类型混合的集合对象排序。字符串都是取首字母进行判断
那么就需要我们自定义排序条件了。
自定义顺序
我们可以自己决定排序的判断条件。
下面将从简单到复杂来介绍各种自定义排序的方法的使用。
sortedBy()
主要自定义sorted的排序逻辑。按照我们定义的函数进行排序。
示例:
fun main(string: Array<String>) {
val intT = listOf("aaa", "vvv", "edde", "asdjiof", "fdioja")
println("实际结果:$intT")
println("自然排序:${intT.sorted()}")
println("自定义排序:${intT.sortedBy { it.length }}")
}
//输出
实际结果:[aaa, vvv, edde, asdjiof, fdioja]
自然排序:[aaa, asdjiof, edde, fdioja, vvv]
自定义排序:[aaa, vvv, edde, fdioja, asdjiof]
例如上面的例子。我们自然排序时将会按照字符串的首字母进行排序。
我们自定义排序,让字符串按照他的字符长度进行排序。
我们在sortedBy 方法中定义的代码。必须是可以进行比较的满足sorted的要求的参数才行。
所以,我们可以定义返回char,int,float 等等基本类型值。
针对自定义对象的排序
示例:
class Zx(val x: Int) {
override fun toString(): String {
return x.toString()
}
}
fun main(string: Array<String>) {
val xx = listOf(Zx(1), Zx(32), Zx(23))
println("实际结果:$xx")
println("自定义排序:${xx.sortedBy { it.x }}")
}
//结果
实际结果:[1, 32, 23]
自定义排序:[1, 23, 32]
那么如果集合对象中是多总元素混杂,该如何排序?
示例:
fun main(string: Array<String>) {
val xx = listOf(1, 0, 0, 5f, 5, 0.3f, 100L, 92)
println("实际结果:$xx")
//例如转成short 进行判断
println("自定义排序:${xx.sortedBy { it.toShort() }}")
}
//输出
实际结果:[1, 0, 0, 5.0, 5, 0.3, 100, 92]
自定义排序:[0, 0, 0.3, 1, 5.0, 5, 92, 100]
如果我们有多个集合,而同时集合的排序方式都是自定义的。
我们可以将排序逻辑写成Comparable 对象。然后分别传给不同的集合对象。
sortedWith()
示例:
fun main(string: Array<String>) {
val xx1 = listOf(1, 0, 23, 54, 5, 12, 54)
val xx2 = listOf(3, 34, 43, 14, 98, 75, 92)
val xx3 = listOf(1, 0, 2, 7, 4, 2, 3)
val sorteds = Comparator { i1: Int, i2: Int -> i1 - i2 }
println(xx1.sortedWith(sorteds))
println(xx2.sortedWith(sorteds))
println(xx3.sortedWith(sorteds))
}
//输出
[0, 1, 5, 12, 23, 54, 54]
[3, 14, 34, 43, 75, 92, 98]
[0, 1, 2, 2, 3, 4, 7]
我们可以自定义自己的Comparator实现两个元素的判断。
但是:Comparator它接受一个类的两个实例并返回它们之间比较的整数结果。
还有其他的写法,例如
示例:
fun main(string: Array<String>) {
val text = listOf("one", "two", "three", "four")
//我们也可以使用 with自定义compareBy,默认两个元素是相同类型的才行
println(text.sortedWith(compareBy { it.length }))
}
//输出
[one, two, four, three]
其他情况
倒序 reversed()
区别于从大到小排序和从小到大排序。
reversed不改变集合元素的位置。只是改变了顺序。
示例:
fun main(string: Array<String>) {
val text = listOf("one", "two", "three", "four")
println(text.reversed())
}
//输出
[four, three, two, one]
也就是说,我们添加数据到集合中的顺序进行了倒置而已。
它还有一个函数asReversed()。
我们使用asReversed 和reversed 都能得到集合的倒叙结果。
但是两者的区别在于
reversed 得到的是一个新的集合对象。源集合对象进行改变。它的结果不会改变。
而asReversed 还是源集合对象,只是得到的一个集合的反向输出结果而已。
两者的使用,根据实际需求进行选择调用。
asReversed要节省内存。毕竟不用拷贝一个新的集合对象。
随机 shuffled()
函数返回一个包含了以随机顺序排序的集合元素的新的 List
。
示例:
fun main(string: Array<String>) {
val text = listOf("one", "two", "three", "four")
println(text.shuffled())
}
//输出
[three, two, one, four]
输出结果是完全随机的。
到这里与排序相关的介绍就结束了。
mutable* 可变集合下排序方法
以上的排序方法,在mutableList等可变集合下。也都是存在的。只是函数名称有一点区别。
例如:
sort(),sortDescending(),sortBy(),sortWith(),shuffle(),reverse()
等等。
功能是一样的,
示例:
fun main(string: Array<String>) {
val numbers = mutableListOf("aa", "bbb", "cccc", "ddddd", "eeeeee")
numbers.sort()
println("从小到大排序: $numbers")
numbers.sortDescending()
println("从大到小排序: $numbers")
numbers.sortBy { it.length }
println("按照字符串长度排序: $numbers")
numbers.sortByDescending { it.last() }
println("按照字符串首字母,从大到小排序: $numbers")
numbers.sortWith(compareBy<String> { it.length }.thenBy { it })
println("自定义,按照字符串长度排序: $numbers")
numbers.shuffle()
println("随机排序: $numbers")
numbers.reverse()
println("倒序: $numbers")
}
//输出
从小到大排序: [aa, bbb, cccc, ddddd, eeeeee]
从大到小排序: [eeeeee, ddddd, cccc, bbb, aa]
按照字符串长度排序: [aa, bbb, cccc, ddddd, eeeeee]
按照字符串首字母,从大到小排序: [eeeeee, ddddd, cccc, bbb, aa]
自定义,按照字符串长度排序: [aa, bbb, cccc, ddddd, eeeeee]
随机排序: [ddddd, cccc, bbb, aa, eeeeee]
倒序: [eeeeee, aa, bbb, cccc, ddddd]