KMP 实现鸿蒙跨端:Kotlin 数字计算器算法
本文介绍了一个基于Kotlin Multiplatform (KMP)的跨平台数字计算器算法实现。该算法支持多种统计功能,包括基础统计(总和、平均值、中位数)、极值分析(最大值、最小值、范围)、离散度计算(方差、标准差)以及分类统计(奇偶、正负、分组统计)。通过KMP技术,该算法可编译为JavaScript在OpenHarmony应用中运行,实现用户输入的实时处理。核心代码展示了Kotlin集合操
·
目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的数字计算器算法系统。这个案例展示了如何使用 Kotlin 的集合操作、数学计算和统计分析来创建一个功能丰富的数据处理工具。通过 KMP,这个算法可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入数字进行实时计算。
算法的特点
- 多功能统计:支持多种统计操作
- 数据分析:提供详细的统计信息
- 用户交互:支持实时输入和处理
- 跨端兼容:一份 Kotlin 代码可同时服务多个平台
- 高效算法:使用 Kotlin 内置函数优化性能
算法功能
1. 基础统计
- 总和:计算所有数字的和
- 平均值:计算算术平均数
- 中位数:计算中间值
2. 极值统计
- 最大值:找出最大的数字
- 最小值:找出最小的数字
- 范围:计算最大值和最小值的差
3. 离散度分析
- 方差:衡量数据的离散程度
- 标准差:方差的平方根
4. 排序操作
- 升序排列:从小到大排序
- 降序排列:从大到小排序
5. 奇偶统计
- 偶数个数:统计偶数个数和百分比
- 奇数个数:统计奇数个数和百分比
6. 正负统计
- 正数个数:统计正数个数
- 负数个数:统计负数个数
- 零的个数:统计零的个数
7. 分组统计
- 按范围分组:将数字按 10 的倍数分组
- 统计每组个数:显示每组中有多少个数字
核心实现
1. 数字解析
val numbers = inputNumbers.split(" ")
.filter { it.isNotEmpty() }
.mapNotNull { it.toIntOrNull() }
2. 基础统计
val sum = numbers.sum()
val count = numbers.size
val average = if (count > 0) sum / count else 0
3. 极值统计
val max = numbers.maxOrNull() ?: 0
val min = numbers.minOrNull() ?: 0
val range = max - min
4. 中位数计算
val sorted = numbers.sorted()
val median = if (count % 2 == 0) {
(sorted[count / 2 - 1] + sorted[count / 2]) / 2
} else {
sorted[count / 2]
}
5. 方差和标准差
val variance = if (count > 0) {
numbers.map { (it - average) * (it - average) }.sum() / count
} else 0
val stdDev = kotlin.math.sqrt(variance.toDouble()).toInt()
6. 分类统计
val evenCount = numbers.count { it % 2 == 0 }
val oddCount = numbers.count { it % 2 != 0 }
val positiveCount = numbers.count { it > 0 }
val negativeCount = numbers.count { it < 0 }
7. 分组统计
val groups = numbers.groupingBy { it / 10 * 10 }
.eachCount()
.toList()
.sortedBy { it.first }
实战案例
案例:完整的数字计算器算法

Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun numberCalculatorAlgorithm(inputNumbers: String = "10 25 30 15 40 20 35"): String {
// 解析输入字符串为数字列表
val numbers = inputNumbers.split(" ")
.filter { it.isNotEmpty() }
.mapNotNull { it.toIntOrNull() }
if (numbers.isEmpty()) {
return "❌ 错误: 没有有效的数字输入\n请输入数字,用空格分隔"
}
// 1. 基础统计
val sum = numbers.sum()
val count = numbers.size
val average = if (count > 0) sum / count else 0
// 2. 极值统计
val max = numbers.maxOrNull() ?: 0
val min = numbers.minOrNull() ?: 0
val range = max - min
// 3. 排序
val sorted = numbers.sorted()
val reversed = numbers.sorted().reversed()
// 4. 中位数
val median = if (count % 2 == 0) {
(sorted[count / 2 - 1] + sorted[count / 2]) / 2
} else {
sorted[count / 2]
}
// 5. 方差和标准差
val variance = if (count > 0) {
numbers.map { (it - average) * (it - average) }.sum() / count
} else 0
val stdDev = kotlin.math.sqrt(variance.toDouble()).toInt()
// 6. 分类统计
val evenCount = numbers.count { it % 2 == 0 }
val oddCount = numbers.count { it % 2 != 0 }
val positiveCount = numbers.count { it > 0 }
val negativeCount = numbers.count { it < 0 }
val zeroCount = numbers.count { it == 0 }
// 7. 百分比统计
val evenPercent = if (count > 0) (evenCount * 100) / count else 0
val oddPercent = if (count > 0) (oddCount * 100) / count else 0
// 8. 分组统计
val groups = numbers.groupingBy { it / 10 * 10 }
.eachCount()
.toList()
.sortedBy { it.first }
val groupStats = groups.map { (range, count) ->
" ${range}-${range + 9}: $count 个数字"
}
return "🔢 数字计算器算法\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"输入数字: $inputNumbers\n" +
"数字个数: $count\n\n" +
"1️⃣ 基础统计:\n" +
" 总和: $sum\n" +
" 平均值: $average\n" +
" 中位数: $median\n\n" +
"2️⃣ 极值统计:\n" +
" 最大值: $max\n" +
" 最小值: $min\n" +
" 范围: $range\n\n" +
"3️⃣ 离散度:\n" +
" 方差: $variance\n" +
" 标准差: $stdDev\n\n" +
"4️⃣ 排序结果:\n" +
" 升序: ${sorted.joinToString(", ")}\n" +
" 降序: ${reversed.joinToString(", ")}\n\n" +
"5️⃣ 奇偶统计:\n" +
" 偶数: $evenCount 个 ($evenPercent%)\n" +
" 奇数: $oddCount 个 ($oddPercent%)\n\n" +
"6️⃣ 正负统计:\n" +
" 正数: $positiveCount 个\n" +
" 负数: $negativeCount 个\n" +
" 零: $zeroCount 个\n\n" +
"7️⃣ 分组统计:\n" +
groupStats.joinToString("\n") + "\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 计算完成!"
}
ArkTS 调用代码(带输入框)
import { numberCalculatorAlgorithm } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
@State caseTitle: string = '数字计算器算法';
@State inputText: string = '10 25 30 15 40 20 35';
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
const results: string[] = [];
const algorithmResult = numberCalculatorAlgorithm(this.inputText);
results.push(algorithmResult);
this.results = results;
this.message = '✓ 计算完成';
} catch (error) {
this.message = `✗ 错误: ${error}`;
}
}
build() {
Column() {
// 顶部标题栏
Row() {
Text('KMP 鸿蒙跨端')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Spacer()
Text('Kotlin 案例')
.fontSize(14)
.fontColor(Color.White)
}
.width('100%')
.height(50)
.backgroundColor('#3b82f6')
.padding({ left: 20, right: 20 })
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.SpaceBetween)
// 案例标题
Column() {
Text(this.caseTitle)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#1f2937')
Text(this.message)
.fontSize(13)
.fontColor('#6b7280')
.margin({ top: 5 })
}
.width('100%')
.padding({ left: 20, right: 20, top: 20, bottom: 15 })
.alignItems(HorizontalAlign.Start)
// 输入框区域
Column() {
Text('输入数字 (用空格分隔):')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#1f2937')
.margin({ bottom: 8 })
TextInput({ placeholder: '例如: 10 25 30 15 40', text: this.inputText })
.width('100%')
.height(60)
.padding(12)
.border({ width: 1, color: '#d1d5db' })
.borderRadius(6)
.onChange((value: string) => {
this.inputText = value
})
Button('计算')
.width('100%')
.height(40)
.margin({ top: 12 })
.backgroundColor('#3b82f6')
.fontColor(Color.White)
.onClick(() => {
this.loadResults()
})
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
// 结果显示区域
Scroll() {
Column() {
ForEach(this.results, (result: string) => {
Column() {
Text(result)
.fontSize(13)
.fontFamily('monospace')
.fontColor('#374151')
.width('100%')
.margin({ top: 10 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.border({ width: 1, color: '#e5e7eb' })
.borderRadius(8)
.margin({ bottom: 12 })
})
}
.width('100%')
.padding({ left: 16, right: 16 })
}
.layoutWeight(1)
.width('100%')
// 底部按钮区域
Row() {
Button('示例数据')
.width('48%')
.height(44)
.backgroundColor('#10b981')
.fontColor(Color.White)
.fontSize(14)
.onClick(() => {
this.inputText = '10 25 30 15 40 20 35'
this.loadResults()
})
Button('清空')
.width('48%')
.height(44)
.backgroundColor('#6b7280')
.fontColor(Color.White)
.fontSize(14)
.onClick(() => {
this.inputText = ''
this.results = []
})
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 20 })
}
.width('100%')
.height('100%')
.backgroundColor('#f9fafb')
}
}
编译过程详解
Kotlin 到 JavaScript 的转换
| Kotlin 特性 | JavaScript 等价物 |
|---|---|
| split() | 字符串分割 |
| mapNotNull() | 过滤和映射 |
| sum() | 数组求和 |
| maxOrNull() | 最大值 |
| minOrNull() | 最小值 |
| count() | 条件计数 |
| groupingBy().eachCount() | 对象计数 |
| sorted() | 排序 |
关键转换点
- 字符串解析:转换为 JavaScript 字符串分割
- 集合操作:转换为数组操作
- 数学计算:保持功能一致
- 统计分析:转换为循环和计数
算法扩展
扩展 1:添加百分位数计算
fun calculatePercentile(numbers: List<Int>, percentile: Double): Int {
val sorted = numbers.sorted()
val index = ((percentile / 100) * sorted.size).toInt()
return sorted.getOrNull(index) ?: 0
}
扩展 2:添加众数计算
fun findMode(numbers: List<Int>): Int {
return numbers.groupingBy { it }
.eachCount()
.maxByOrNull { it.value }
?.key ?: 0
}
扩展 3:添加四分位数
fun calculateQuartiles(numbers: List<Int>): Triple<Int, Int, Int> {
val sorted = numbers.sorted()
val q1 = sorted[sorted.size / 4]
val q2 = sorted[sorted.size / 2]
val q3 = sorted[3 * sorted.size / 4]
return Triple(q1, q2, q3)
}
扩展 4:添加异常值检测
fun detectOutliers(numbers: List<Int>): List<Int> {
val mean = numbers.average()
val stdDev = kotlin.math.sqrt(
numbers.map { (it - mean) * (it - mean) }.average()
)
return numbers.filter { kotlin.math.abs(it - mean) > 3 * stdDev }
}
最佳实践
1. 使用内置函数
// ✅ 好:使用 sum()
val total = numbers.sum()
// ❌ 不好:手动求和
var total = 0
for (num in numbers) total += num
2. 使用 count() 统计
// ✅ 好:使用 count()
val evenCount = numbers.count { it % 2 == 0 }
// ❌ 不好:使用 filter().size
val evenCount = numbers.filter { it % 2 == 0 }.size
3. 使用 maxOrNull() 和 minOrNull()
// ✅ 好:使用 maxOrNull()
val max = numbers.maxOrNull() ?: 0
// ❌ 不好:手动比较
var max = numbers[0]
for (num in numbers) if (num > max) max = num
4. 链式操作
// ✅ 好:链式操作
val result = inputNumbers.split(" ")
.filter { it.isNotEmpty() }
.mapNotNull { it.toIntOrNull() }
// ❌ 不好:多个中间变量
val parts = inputNumbers.split(" ")
val filtered = parts.filter { it.isNotEmpty() }
val result = filtered.mapNotNull { it.toIntOrNull() }
常见问题
Q1: 如何处理浮点数?
A: 使用 toDoubleOrNull() 代替 toIntOrNull():
val numbers = inputNumbers.split(" ")
.filter { it.isNotEmpty() }
.mapNotNull { it.toDoubleOrNull() }
Q2: 如何计算加权平均数?
A: 使用 zip 和 map:
fun weightedAverage(values: List<Int>, weights: List<Int>): Double {
val sum = values.zip(weights) { v, w -> v * w }.sum()
val weightSum = weights.sum()
return sum.toDouble() / weightSum
}
Q3: 如何检测数据异常?
A: 使用标准差检测:
fun isOutlier(value: Int, numbers: List<Int>): Boolean {
val mean = numbers.average()
val stdDev = kotlin.math.sqrt(
numbers.map { (it - mean) * (it - mean) }.average()
)
return kotlin.math.abs(value - mean) > 3 * stdDev
}
Q4: 如何处理空输入?
A: 添加验证逻辑:
if (numbers.isEmpty()) {
return "❌ 错误: 没有有效的数字输入"
}
Q5: 如何优化大数据集的性能?
A: 使用 Sequence 代替 List:
val numbers = inputNumbers.split(" ")
.asSequence()
.filter { it.isNotEmpty() }
.mapNotNull { it.toIntOrNull() }
.toList()
总结
关键要点
- ✅ 使用 Kotlin 内置集合函数
- ✅ 使用 count() 进行统计
- ✅ 使用 groupingBy() 进行分组
- ✅ 使用链式操作简化代码
- ✅ KMP 能无缝编译到 JavaScript
下一步
- 实现更多统计函数(百分位数、众数等)
- 添加数据可视化
- 实现数据导入导出
- 添加高级统计分析
- 实现数据对比功能
参考资源
更多推荐


所有评论(0)