KMP 实现鸿蒙跨端:Kotlin 数字计算器算法
本文介绍了基于Kotlin Multiplatform的数字计算器算法实现,支持跨平台部署到鸿蒙应用。该算法提供丰富的统计功能,包括基础统计(总和、平均值、中位数)、极值分析(最大/最小值、范围)、离散度计算(方差、标准差)以及分类统计(奇偶、正负数)。核心实现采用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() }
这段代码实现了从字符串输入中提取有效数字的过程。首先使用 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
这段代码计算了数字集合的三个基本统计量。numbers.sum() 直接调用 Kotlin 内置函数计算所有数字的总和,numbers.size 获取列表中元素的个数。对于平均值的计算,使用了条件表达式 if (count > 0) 来避免除以零的错误,当列表非空时计算 sum / count,否则返回 0。这种防御性编程的做法确保了算法的健壮性。
3. 极值统计
val max = numbers.maxOrNull() ?: 0
val min = numbers.minOrNull() ?: 0
val range = max - min
这段代码找出数字集合中的最大值和最小值,然后计算它们的差值(范围)。maxOrNull() 和 minOrNull() 是 Kotlin 提供的安全函数,当列表为空时返回 null,而不会抛出异常。通过使用 Elvis 操作符 ?: 0,我们在函数返回 null 时提供默认值 0,这样可以优雅地处理空列表的情况。范围值 range 反映了数据的分布宽度,是衡量数据离散程度的一个简单指标。
4. 中位数计算
val sorted = numbers.sorted()
val median = if (count % 2 == 0) {
(sorted[count / 2 - 1] + sorted[count / 2]) / 2
} else {
sorted[count / 2]
}
中位数是统计学中的重要概念,代表数据集的中间值。这段代码首先对数字进行升序排列,然后根据列表长度的奇偶性采用不同的计算方法。当元素个数为偶数时,中位数是中间两个元素的平均值;当元素个数为奇数时,中位数就是正中间的元素。这个算法通过 count % 2 == 0 来判断奇偶性,然后用相应的索引访问排序后列表中的元素。
5. 方差和标准差
val variance = if (count > 0) {
numbers.map { (it - average) * (it - average) }.sum() / count
} else 0
val stdDev = kotlin.math.sqrt(variance.toDouble()).toInt()
方差和标准差是衡量数据离散程度的重要统计指标。这段代码首先计算方差:对每个数字减去平均值后平方,然后求和再除以元素个数。使用 map 函数将每个元素转换为 (it - average) * (it - average),然后 sum() 求和。标准差是方差的平方根,代码使用 kotlin.math.sqrt() 函数计算平方根,并通过 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 }
这段代码对数字进行多维度的分类统计。count() 函数接收一个 lambda 表达式作为条件,返回满足条件的元素个数。第一行统计偶数个数,使用 it % 2 == 0 判断是否能被 2 整除;第二行统计奇数个数,使用 it % 2 != 0 判断。第三行和第四行分别统计正数和负数的个数。这种方式比使用 filter().size 更高效,因为 count() 不需要创建中间的过滤列表,直接计数即可。
7. 分组统计
val groups = numbers.groupingBy { it / 10 * 10 }
.eachCount()
.toList()
.sortedBy { it.first }
这段代码实现了按范围分组的功能。groupingBy { it / 10 * 10 } 将数字按照 10 的倍数进行分组,例如 15 和 23 都会被分到 10-19 这个组(因为 15/1010=10,23/1010=20)。eachCount() 计算每个组中有多少个元素,返回一个 Map。toList() 将 Map 转换为 Pair 列表,每个 Pair 包含分组的键和对应的计数。最后 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" +
"✅ 计算完成!"
}
这是整个数字计算器算法的核心实现函数。函数使用 @OptIn(ExperimentalJsExport::class) 和 @JsExport 注解,使其可以被编译成 JavaScript 并在 ArkTS 中调用。函数接收一个字符串参数 inputNumbers,包含用空格分隔的数字。首先进行输入验证,如果没有有效数字则返回错误提示。然后依次计算七个方面的统计信息:基础统计(总和、平均值、中位数)、极值统计(最大值、最小值、范围)、排序结果、方差和标准差、奇偶分类、正负分类以及按范围分组。最后使用字符串拼接构建格式化的输出结果,包含表情符号和分隔线,使输出更加美观易读。
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')
}
}
这段 ArkTS 代码是鸿蒙应用的用户界面实现,通过 import 语句导入之前编译的 Kotlin 函数。使用 @State 装饰器定义四个响应式状态变量:message 用于显示状态信息,results 存储计算结果,caseTitle 显示标题,inputText 存储用户输入。aboutToAppear() 生命周期函数在组件加载时自动调用 loadResults() 进行初始计算。loadResults() 方法调用 Kotlin 函数并处理结果,使用 try-catch 捕获异常。build() 方法构建整个 UI 布局,分为五个部分:顶部蓝色标题栏、案例标题和状态信息、用户输入区域(包含文本输入框和计算按钮)、可滚动的结果显示区域以及底部的示例数据和清空按钮。整个界面采用响应式设计,使用 Flexbox 布局和现代化的配色方案。
编译过程详解
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
}
百分位数是统计学中用来描述数据分布的重要指标。这个函数计算给定百分位数对应的值。首先对输入数字进行升序排列,然后根据百分位数计算对应的索引位置:将百分位数除以 100 得到比例,乘以列表大小得到索引。使用 getOrNull(index) 安全地访问列表元素,如果索引超出范围则返回 null,通过 Elvis 操作符 ?: 0 提供默认值 0。例如,第 75 个百分位数表示有 75% 的数据小于这个值。
扩展 2:添加众数计算
fun findMode(numbers: List<Int>): Int {
return numbers.groupingBy { it }
.eachCount()
.maxByOrNull { it.value }
?.key ?: 0
}
众数是指在数据集中出现频率最高的数值。这个函数使用 groupingBy { it } 将相同的数字分组,eachCount() 计算每个数字出现的次数,返回一个 Map,其中键是数字,值是出现次数。maxByOrNull { it.value } 找到出现次数最多的组,返回一个 Pair(数字和出现次数)。使用安全调用操作符 ?.key 获取这个 Pair 的键(即众数),如果没有找到则返回 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)
}
四分位数将数据分成四个相等的部分,是描述数据分布的重要工具。这个函数首先对数据进行升序排列,然后计算三个四分位数:Q1(第一四分位数)位于 25% 的位置,Q2(第二四分位数,即中位数)位于 50% 的位置,Q3(第三四分位数)位于 75% 的位置。通过计算 sorted.size / 4、sorted.size / 2 和 3 * sorted.size / 4 得到对应的索引。函数使用 Triple 数据类返回三个值,这是 Kotlin 提供的便捷方式来返回多个相关的值。四分位数常用于箱线图的绘制和异常值的检测。
扩展 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 }
}
异常值检测是数据清洁的重要步骤,用于识别和处理不符合正常分布的数据。这个函数使用三西格玛原则(3-sigma rule)进行异常值检测。首先计算数据的平均值 mean,然后计算标准差 stdDev。对于每个数据点,计算其与平均值的偏离程度,如果偏离超过 3 倍标准差,则认为是异常值。使用 kotlin.math.abs() 计算绝对值,filter() 筛选出所有异常值。这个方法基于正态分布的性质,在正态分布中,99.7% 的数据应该在 3 倍标准差范围内。
最佳实践
1. 使用内置函数
// ✅ 好:使用 sum()
val total = numbers.sum()
// ❌ 不好:手动求和
var total = 0
for (num in numbers) total += num
这个最佳实践展示了如何选择更优雅和高效的代码风格。使用 Kotlin 内置的 sum() 函数比手动循环求和更简洁、更易读,也更不容易出错。内置函数通常经过优化,性能也更好。手动循环的方式需要定义可变变量 total,这违反了函数式编程的原则。sum() 函数是不可变的,返回一个新的值,符合现代编程的最佳实践。
2. 使用 count() 统计
// ✅ 好:使用 count()
val evenCount = numbers.count { it % 2 == 0 }
// ❌ 不好:使用 filter().size
val evenCount = numbers.filter { it % 2 == 0 }.size
这个例子说明了性能优化的重要性。count() 函数直接计算满足条件的元素个数,而 filter().size 先创建一个新的过滤列表,然后再获取其大小。对于大数据集,count() 方式更高效,因为它不需要创建中间的列表对象,直接遍历原列表进行计数。从代码可读性的角度,count() 也更清晰地表达了意图:我们只关心满足条件的元素个数,而不是获取这些元素本身。
3. 使用 maxOrNull() 和 minOrNull()
// ✅ 好:使用 maxOrNull()
val max = numbers.maxOrNull() ?: 0
// ❌ 不好:手动比较
var max = numbers[0]
for (num in numbers) if (num > max) max = num
这个最佳实践强调了使用内置函数的安全性和便利性。maxOrNull() 函数安全地处理空列表的情况,返回 null 而不是抛出异常。手动比较的方式在列表为空时会直接抛出 IndexOutOfBoundsException,需要额外的错误处理。使用 maxOrNull() 配合 Elvis 操作符 ?: 0,代码更简洁,也更安全。这种防御性编程的做法可以避免许多潜在的 bug。
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() }
链式操作是函数式编程的核心特性,能显著提高代码的可读性和简洁性。使用链式操作,我们可以清晰地看到数据的转换流程:先分割字符串,再过滤空字符串,最后转换为整数。这种方式避免了创建多个中间变量,减少了命名的负担,也减少了内存占用。链式操作的另一个优势是它表达了数据的转换意图,使代码更容易理解。在 Kotlin 中,链式操作是一种习惯用法,能写出更 Kotlin-like 的代码。
常见问题
Q1: 如何处理浮点数?
A: 使用 toDoubleOrNull() 代替 toIntOrNull():
val numbers = inputNumbers.split(" ")
.filter { it.isNotEmpty() }
.mapNotNull { it.toDoubleOrNull() }
当需要处理包含小数点的数字时,应该使用 toDoubleOrNull() 而不是 toIntOrNull()。toDoubleOrNull() 能够将字符串转换为双精度浮点数,支持小数点和科学计数法。这个改动只需要改变一个函数名,其他的链式操作保持不变。使用浮点数后,所有的统计计算也会自动使用浮点数进行,提供更高的精度。需要注意的是,浮点数运算可能存在精度问题,在某些对精度要求很高的场景中,可能需要使用 BigDecimal 类。
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
}
加权平均数用于计算不同重要性的数据的平均值。这个函数接收两个列表:数值列表和对应的权重列表。zip() 函数将两个列表的元素一一配对,然后使用 lambda 表达式 { v, w -> v * w } 计算每对元素的乘积(数值乘以权重)。sum() 计算所有乘积的总和。weights.sum() 计算所有权重的总和。最后,加权平均数等于加权总和除以权重总和。例如,如果有三个考试成绩 [80, 90, 85],权重分别为 [1, 2, 1],则加权平均数为 (80×1 + 90×2 + 85×1) / (1+2+1) = 86.25。
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
}
这个函数使用统计学中的三西格玛原则来检测单个数据点是否为异常值。首先计算数据集的平均值 mean,然后计算标准差 stdDev。标准差的计算过程是:对每个数据点计算其与平均值的偏差,平方后求平均值,最后取平方根。然后检查给定值与平均值的偏离程度是否超过 3 倍标准差。如果超过,则认为这个值是异常值。这个方法基于正态分布的性质,在正态分布中,99.7% 的数据应该在平均值的 3 倍标准差范围内,所以超出这个范围的数据很可能是异常的。
Q4: 如何处理空输入?
A: 添加验证逻辑:
if (numbers.isEmpty()) {
return "❌ 错误: 没有有效的数字输入"
}
处理空输入是编写健壮代码的必要步骤。这段代码在开始进行任何计算之前,先检查数字列表是否为空。如果为空,立即返回一个错误提示信息,而不是继续执行可能导致异常的计算。这种防御性编程的做法可以提高用户体验,用户会看到清晰的错误提示,而不是程序崩溃或返回错误的结果。在实际应用中,应该在所有可能接收用户输入的地方添加这样的验证逻辑。
Q5: 如何优化大数据集的性能?
A: 使用 Sequence 代替 List:
val numbers = inputNumbers.split(" ")
.asSequence()
.filter { it.isNotEmpty() }
.mapNotNull { it.toIntOrNull() }
.toList()
当处理大数据集时,使用 Sequence 而不是 List 可以显著提高性能。Sequence 是一种惰性求值的集合,它不会立即创建中间的列表对象,而是在需要时才进行计算。在这个例子中,asSequence() 将列表转换为序列,然后链式调用 filter() 和 mapNotNull()。这些操作不会立即执行,而是被记录下来。只有在最后调用 toList() 时,才会一次性执行所有的操作,遍历原列表一次。相比之下,如果使用 List 的链式操作,每个操作都会创建一个新的中间列表,对于大数据集会造成大量的内存占用和性能开销。
总结
关键要点
- ✅ 使用 Kotlin 内置集合函数
- ✅ 使用 count() 进行统计
- ✅ 使用 groupingBy() 进行分组
- ✅ 使用链式操作简化代码
- ✅ KMP 能无缝编译到 JavaScript
下一步
- 实现更多统计函数(百分位数、众数等)
- 添加数据可视化
- 实现数据导入导出
- 添加高级统计分析
- 实现数据对比功能
参考资源
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)