KMP 实现鸿蒙跨端:Kotlin 排序操作和数据排列指南
本文介绍了Kotlin Multiplatform在鸿蒙跨端开发中的排序操作,涵盖基础排序(升序、降序、反转)、高级排序(条件排序)及性能优化。通过KMP框架,排序代码可编译为JavaScript在OpenHarmony运行,实现跨平台复用。文章提供了具体代码示例,包括Kotlin实现、编译后的JavaScript代码及ArkTS调用方式,帮助开发者掌握数据排序的核心技术,提升跨端开发效率。

目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中进行排序操作和数据排列。排序是数据处理中最常见的操作之一。通过 KMP,这些排序操作可以无缝编译到 JavaScript,在 OpenHarmony 应用中高效运行。
为什么需要学习排序操作?
- 数据展示:按特定顺序展示数据,提升用户体验
- 数据分析:排序后的数据便于分析和查找
- 业务逻辑:实现排序功能是很多应用的核心需求
- 代码简洁:使用函数式排序比手写排序算法更简洁
- 跨端兼容:排序操作在编译到 JavaScript 时表现出色,完美支持 OpenHarmony
- 代码复用:一份 Kotlin 代码可同时服务多个平台
基础排序
sorted - 升序排序
对集合进行升序排序。
val numbers = listOf(5, 2, 8, 1, 9, 3)
val sorted = numbers.sorted()
println(sorted) // [1, 2, 3, 5, 8, 9]
val words = listOf("Zebra", "Apple", "Mango")
val sortedWords = words.sorted()
println(sortedWords) // [Apple, Mango, Zebra]
代码说明:
这段代码演示了 sorted() 函数的升序排序功能。对于数字列表,sorted() 将元素按从小到大的顺序排列。对于字符串列表,sorted() 按字母顺序排列(字典序)。sorted() 函数返回一个新的排序后的列表,原列表保持不变。
sortedDescending - 降序排序
对集合进行降序排序。
val numbers = listOf(5, 2, 8, 1, 9, 3)
val sorted = numbers.sortedDescending()
println(sorted) // [9, 8, 5, 3, 2, 1]
val words = listOf("Zebra", "Apple", "Mango")
val sortedWords = words.sortedDescending()
println(sortedWords) // [Zebra, Mango, Apple]
代码说明:
这段代码演示了 sortedDescending() 函数的降序排序功能。对于数字列表,sortedDescending() 将元素按从大到小的顺序排列。对于字符串列表,sortedDescending() 按反向字母顺序排列。sortedDescending() 函数返回一个新的排序后的列表,原列表保持不变。
reverse - 反转
反转集合中元素的顺序。
val numbers = listOf(1, 2, 3, 4, 5)
val reversed = numbers.reversed()
println(reversed) // [5, 4, 3, 2, 1]
// 原集合不变
println(numbers) // [1, 2, 3, 4, 5]
代码说明:
这段代码演示了 reversed() 函数的反转功能。reversed() 将列表中的元素顺序完全反转,第一个元素变成最后一个,最后一个元素变成第一个。reversed() 函数返回一个新的反转后的列表,原列表保持不变。这个函数对于需要逆序遍历数据的场景非常有用。
高级排序
sortedBy - 按条件排序
Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun sortedExample(): String {
val numbers = listOf(5, 2, 8, 1, 9, 3, 7, 4, 6)
val words = listOf("Zebra", "Apple", "Mango", "Banana", "Cherry")
// 升序排序
val sortedNumbers = numbers.sorted()
// 降序排序
val reverseSorted = numbers.sortedDescending()
// 按长度排序
val sortedByLength = words.sortedBy { it.length }
return "原始数字: ${numbers.joinToString(", ")}\n" +
"升序: ${sortedNumbers.joinToString(", ")}\n" +
"降序: ${reverseSorted.joinToString(", ")}\n" +
"按长度排序: ${sortedByLength.joinToString(", ")}"
}
代码说明:
这是排序操作的完整 Kotlin 实现。函数使用 @JsExport 装饰器将其导出为 JavaScript 可调用的函数。首先创建数字列表和字符串列表。使用 sorted() 进行升序排序。使用 sortedDescending() 进行降序排序。使用 sortedBy { it.length } 按字符串长度升序排序,Lambda 表达式 { it.length } 指定排序的关键字。最后使用 joinToString() 将列表转换为逗号分隔的字符串,并格式化输出。
编译后的 JavaScript 代码
function sortedExample() {
var numbers = listOf_0([5, 2, 8, 1, 9, 3, 7, 4, 6]);
var words = listOf_0(['Zebra', 'Apple', 'Mango', 'Banana', 'Cherry']);
// 升序排序
var sortedNumbers = sorted(numbers);
// 降序排序
var reverseSorted = sortedDescending(numbers);
// 按长度排序
// Inline function 'kotlin.collections.sortedBy' call
// Inline function 'kotlin.comparisons.compareBy' call
var tmp = sortedExample$lambda;
var tmp$ret$0 = new sam$kotlin_Comparator$0(tmp);
var sortedByLength = sortedWith(words, tmp$ret$0);
return '原始数字: ' + joinToString_0(numbers, ', ') + '\n' +
('升序: ' + joinToString_0(sortedNumbers, ', ') + '\n') +
('降序: ' + joinToString_0(reverseSorted, ', ') + '\n') +
('按长度排序: ' + joinToString_0(sortedByLength, ', '));
}
function sortedExample$lambda(a, b) {
// Inline function 'kotlin.comparisons.compareValuesBy' call
// Inline function 'sortedExample.<anonymous>' call
var tmp = a.length;
var tmp_0 = b.length;
return tmp - tmp_0 | 0;
}
代码说明:
这是 Kotlin 代码编译到 JavaScript 后的结果。可以看到 Kotlin 的排序函数被转换为 JavaScript 等价物:sorted() 变成 sorted() 函数调用,sortedDescending() 变成 sortedDescending() 函数调用。sortedBy 中的 Lambda 表达式被编译成一个单独的函数 sortedExample$lambda,该函数实现了比较逻辑。joinToString() 被转换为 joinToString_0() 函数。虽然编译后的代码看起来复杂,但它保留了原始 Kotlin 代码的逻辑和功能。
ArkTS 调用代码
import { sortedExample } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
// 调用 Kotlin 编译的 JavaScript 函数
const sortedResult = sortedExample();
this.results = [sortedResult];
this.message = '案例已加载';
} catch (error) {
this.message = `错误: ${error}`;
}
}
build() {
Column() {
Text('Kotlin Sorted 排序操作演示')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
Text(this.message)
.fontSize(14)
.fontColor(Color.Gray)
.margin({ bottom: 15 })
Scroll() {
Column() {
ForEach(this.results, (result: string) => {
Text(result)
.fontSize(12)
.fontFamily('monospace')
.padding(12)
.width('100%')
.backgroundColor(Color.White)
.border({ width: 1, color: Color.Gray })
.borderRadius(8)
})
}
.width('100%')
.padding({ left: 15, right: 15 })
}
.layoutWeight(1)
.width('100%')
Button('刷新结果')
.width('80%')
.height(40)
.margin({ bottom: 20 })
.onClick(() => {
this.loadResults();
})
}
.width('100%')
.height('100%')
.backgroundColor('#f5f5f5')
}
}
代码说明:
这是 OpenHarmony ArkTS 页面的完整实现。首先导入 Kotlin 编译生成的 sortedExample 函数。定义三个状态变量:message 显示操作状态,results 存储排序结果。aboutToAppear() 生命周期钩子在页面加载时自动调用 loadResults() 进行初始排序。loadResults() 方法调用 Kotlin 函数获取排序结果,更新状态信息,使用 try-catch 捕获异常。build() 方法定义 UI 布局:顶部显示标题和状态,中间是可滚动的结果显示区域,下方是刷新按钮。使用等宽字体显示排序结果,保持格式对齐。
执行流程说明
- Kotlin 源代码:定义
sortedExample()函数,使用 sorted、sortedDescending、sortedBy 进行排序 - 编译过程:Gradle 使用 KMP 编译器将 Kotlin 代码编译成 JavaScript
- JavaScript 输出:编译器生成优化的 JavaScript 代码,使用内置排序函数实现排序逻辑
- ArkTS 调用:在 OpenHarmony 应用中导入并调用编译后的 JavaScript 函数
- 结果展示:在 UI 中显示排序结果
sortedByDescending - 按条件降序排序
val words = listOf("Zebra", "Apple", "Mango", "Banana")
// 按长度降序排序
val sortedByLength = words.sortedByDescending { it.length }
println(sortedByLength) // [Zebra, Mango, Apple, Banana]
代码说明:
这段代码演示了 sortedByDescending() 函数的按条件降序排序功能。sortedByDescending { it.length } 按字符串长度从长到短排序。Lambda 表达式 { it.length } 指定排序的关键字。结果中长度为 5 的单词(Zebra、Mango)排在前面,长度为 4 的单词(Apple、Banana)排在后面。这个函数对于需要按某个属性降序排列的场景非常有用。
自定义排序
sortedWith - 使用自定义比较器
data class Person(val name: String, val age: Int)
val people = listOf(
Person("Alice", 30),
Person("Bob", 25),
Person("Charlie", 35)
)
// 按年龄排序
val byAge = people.sortedWith(compareBy { it.age })
println(byAge)
// [Person(Bob, 25), Person(Alice, 30), Person(Charlie, 35)]
// 按名字排序
val byName = people.sortedWith(compareBy { it.name })
println(byName)
// [Person(Alice, 30), Person(Bob, 25), Person(Charlie, 35)]
// 多条件排序:先按年龄,再按名字
val byAgeAndName = people.sortedWith(compareBy({ it.age }, { it.name }))
代码说明:
这段代码演示了 sortedWith() 函数的自定义排序功能。首先定义一个数据类 Person 包含名字和年龄。使用 sortedWith(compareBy { it.age }) 按年龄升序排序。使用 sortedWith(compareBy { it.name }) 按名字升序排序。使用 sortedWith(compareBy({ it.age }, { it.name })) 进行多条件排序:先按年龄升序,如果年龄相同则按名字升序。compareBy() 函数创建一个比较器,sortedWith() 使用这个比较器进行排序。这个方法对于复杂的排序需求非常灵活。
实战案例
案例:排序操作的实际应用
在上面的"高级排序"部分已经展示了完整的三层代码示例(Kotlin、JavaScript、ArkTS)。这个 sortedExample() 案例演示了:
- 基础排序:升序排序、降序排序
- 高级排序:按条件排序(按长度)
- 编译过程:展示了 Kotlin 代码如何编译成 JavaScript
- 实际调用:展示了如何在 ArkTS 中调用编译后的函数
扩展应用场景
在实际项目中,可以基于 sortedExample() 的模式进行扩展:
- 用户列表排序:按名字、年龄、注册时间等排序
- 商品列表排序:按价格、销量、评分等排序
- 订单列表排序:按日期、金额、状态等排序
- 搜索结果排序:按相关性、时间、热度等排序
所有这些应用都遵循相同的 Kotlin → JavaScript → ArkTS 的编译和调用流程。
性能优化
1. 选择合适的排序方式
// ✅ 好:使用 sorted()
val sorted = numbers.sorted()
// ❌ 不好:使用 sortedBy()
val sorted = numbers.sortedBy { it }
代码说明:
这个示例对比了两种排序方法的性能。第一种方法使用 sorted() 直接排序,是最优的选择,因为它针对可比较类型进行了优化。第二种方法使用 sortedBy { it } 虽然功能相同,但需要额外的 Lambda 表达式处理,性能略低。最佳实践是:对于简单的排序,使用 sorted() 或 sortedDescending();对于复杂的排序条件,才使用 sortedBy() 或 sortedWith()。
2. 避免多次排序
// ❌ 不好:多次排序
val sorted1 = numbers.sorted()
val sorted2 = numbers.sortedDescending()
// ✅ 好:一次排序后反转
val sorted = numbers.sorted()
val reversed = sorted.reversed()
代码说明:
这个示例对比了排序的性能优化。第一种方法对同一个列表进行两次完整的排序操作,时间复杂度为 O(2n log n)。第二种方法先进行一次排序,然后使用 reversed() 反转结果,时间复杂度为 O(n log n + n),效率更高。最佳实践是:如果需要升序和降序两个版本,应该先排序再反转,而不是分别排序。
3. 使用 Sequence 处理大数据
// ✅ 好:使用 Sequence
val result = numbers
.asSequence()
.filter { it > 5 }
.sortedBy { it }
.toList()
// ❌ 不好:创建多个中间列表
val result = numbers
.filter { it > 5 }
.sortedBy { it }
代码说明:
这个示例对比了处理大数据集的方法。第一种方法使用 asSequence() 将列表转换为序列,序列是惰性求值的,只在最后 toList() 时才执行所有操作。这样可以避免创建中间列表,节省内存。第二种方法使用集合操作,filter() 会创建一个中间列表,然后 sortedBy() 再创建另一个中间列表,浪费内存。最佳实践是:处理大数据集时,使用 Sequence 进行链式操作。
4. 缓存排序结果
// ✅ 好:缓存排序结果
val sorted = numbers.sorted()
val first = sorted.first()
val last = sorted.last()
// ❌ 不好:多次排序
val first = numbers.sorted().first()
val last = numbers.sorted().last()
代码说明:
这个示例对比了排序结果的缓存方法。第一种方法先进行一次排序并缓存结果,然后多次使用这个结果,只需要一次 O(n log n) 的排序操作。第二种方法每次获取数据时都进行一次排序,总共需要两次 O(n log n) 的排序操作,浪费计算资源。最佳实践是:如果需要多次使用排序结果,应该先排序并缓存,然后重复使用。
常见问题
Q1: sorted 和 sortedBy 有什么区别?
A:
- sorted:直接排序,用于可比较的类型
- sortedBy:按指定属性排序,用于复杂对象
val numbers = listOf(5, 2, 8, 1, 9)
val sorted = numbers.sorted() // [1, 2, 5, 8, 9]
val words = listOf("Zebra", "Apple", "Mango")
val byLength = words.sortedBy { it.length } // [Apple, Zebra, Mango]
代码说明:
这个示例对比了 sorted() 和 sortedBy() 的区别。sorted() 直接对可比较的类型(如数字、字符串)进行排序,使用类型的自然顺序。sortedBy() 接收一个 Lambda 表达式,指定排序的关键字,适用于复杂对象或需要自定义排序逻辑的场景。在这个例子中,sortedBy { it.length } 按字符串长度排序,而不是字母顺序。
Q2: 如何进行多条件排序?
A: 使用 sortedWith 和 compareBy
data class Person(val name: String, val age: Int)
val people = listOf(
Person("Alice", 30),
Person("Bob", 25),
Person("Alice", 25)
)
// 先按名字,再按年龄
val sorted = people.sortedWith(compareBy({ it.name }, { it.age }))
// [Person(Alice, 25), Person(Alice, 30), Person(Bob, 25)]
代码说明:
这段代码演示了多条件排序。使用 compareBy() 创建一个比较器,接收多个 Lambda 表达式作为排序条件。第一个条件是名字,第二个条件是年龄。排序时先按名字升序排列,如果名字相同则按年龄升序排列。结果中两个 Alice 按年龄排序(25 在 30 之前),Bob 排在最后。这个方法对于需要按多个属性排序的场景非常有用。
Q3: 如何进行不区分大小写的排序?
A: 使用 sortedBy 和 lowercase()
val words = listOf("Zebra", "apple", "Mango", "BANANA")
// 不区分大小写排序
val sorted = words.sortedBy { it.lowercase() }
println(sorted) // [apple, BANANA, Mango, Zebra]
代码说明:
这段代码演示了不区分大小写的排序。使用 sortedBy { it.lowercase() } 将每个字符串转换为小写后进行排序。这样无论原字符串是大写、小写还是混合大小写,都会按照小写字母的顺序排列。结果中所有单词都按字母顺序排列,不受大小写影响。这个方法对于需要忽略大小写的排序场景非常有用。
Q4: 如何对可变集合进行原地排序?
A: 使用 sort() 或 sortDescending()
val numbers = mutableListOf(5, 2, 8, 1, 9)
// 原地升序排序
numbers.sort()
println(numbers) // [1, 2, 5, 8, 9]
// 原地降序排序
numbers.sortDescending()
println(numbers) // [9, 8, 5, 2, 1]
代码说明:
这段代码演示了原地排序。sort() 和 sortDescending() 直接修改可变列表,不返回新列表。与 sorted() 和 sortedDescending() 不同,这两个函数不创建新的列表对象,而是在原列表上进行排序。这种方法对于处理大型数据集时更节省内存。注意:这些函数只能用于可变列表(MutableList),不能用于不可变列表(List)。
Q5: 排序的时间复杂度是多少?
A: Kotlin 的排序使用快速排序或合并排序,时间复杂度为 O(n log n)
val numbers = listOf(5, 2, 8, 1, 9, 3, 7, 4, 6)
// 时间复杂度:O(n log n)
val sorted = numbers.sorted()
// 时间复杂度:O(n log n)
val byLength = words.sortedBy { it.length }
代码说明:
这段代码说明了排序的时间复杂度。Kotlin 的 sorted() 和 sortedBy() 函数使用高效的排序算法(通常是快速排序或合并排序),时间复杂度为 O(n log n),其中 n 是列表的元素个数。这意味着即使列表很大,排序的性能也是可以接受的。空间复杂度通常为 O(n),因为需要创建新的排序后的列表。了解时间复杂度对于编写高效的代码非常重要。
总结
关键要点
- ✅
sorted()和sortedDescending()是最常用的排序函数 - ✅
sortedBy()用于按属性排序 - ✅
sortedWith()用于自定义排序逻辑 - ✅
reversed()用于反转顺序 - ✅ 对可变集合使用
sort()进行原地排序
更多推荐




所有评论(0)