目录

  1. 概述
  2. 算法功能
  3. 核心实现
  4. 实战案例
  5. 编译过程详解
  6. 算法扩展
  7. 最佳实践
  8. 常见问题

概述

本文档介绍如何在 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() 排序

关键转换点

  1. 字符串解析:转换为 JavaScript 字符串分割
  2. 集合操作:转换为数组操作
  3. 数学计算:保持功能一致
  4. 统计分析:转换为循环和计数

算法扩展

扩展 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

下一步

  1. 实现更多统计函数(百分位数、众数等)
  2. 添加数据可视化
  3. 实现数据导入导出
  4. 添加高级统计分析
  5. 实现数据对比功能

参考资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐