在这里插入图片描述

概述

数组去重与分组统计是计算机科学中的经典问题,涉及数据结构设计、算法优化和性能分析。本文基于 Kotlin Multiplatform(KMP)与 OpenHarmony,深入探讨如何利用哈希表(Hash Table)数据结构实现高效的数组去重、分组统计和交叉分析,并通过 ArkTS 实现跨平台的用户界面。

核心算法设计

1. 哈希表理论基础

哈希表(Hash Table)是一种基于哈希函数进行数据访问的数据结构,在平均情况下,其查找、插入和删除操作的时间复杂度均为 O(1)。在 Kotlin 中,SetMap 的实现底层使用了哈希表,这为我们提供了高效的集合操作能力。

哈希表的优势
  • 时间复杂度: 平均 O(1) 的查找和插入性能
  • 空间换时间: 通过额外的内存空间换取查找速度
  • 去重天然支持: Set 数据结构天然具有去重特性

2. 算法架构设计

@JsExport
fun arrayDeduplicationAnalyzer(inputData: String): String {
    // 步骤1: 数据解析与预处理
    val groups = parseArrayGroups(sanitized)
    
    // 步骤2: 全局统计分析(使用 Set 去重,Map 统计频次)
    val allItems = groups.flatMap { it.items }
    val globalUnique = allItems.toSet()  // O(n) 时间复杂度
    val globalFrequency = allItems.groupingBy { it }.eachCount()  // O(n) 时间复杂度
    
    // 步骤3: 分组分析(每组独立统计)
    groups.forEach { group ->
        val uniqueSet = group.items.toSet()
        val frequency = group.items.groupingBy { it }.eachCount()
        val sortedByFreq = frequency.toList().sortedByDescending { it.second }  // O(k log k)
    }
    
    // 步骤4: 交叉分析(集合交集运算)
    val intersection = groups.map { it.items.toSet() }
        .reduce { acc, set -> acc.intersect(set) }  // O(n*m)
}
算法复杂度分析
操作 时间复杂度 空间复杂度 说明
数据解析 O(n) O(n) n 为总元素数
全局去重 O(n) O(k) k 为唯一元素数
频次统计 O(n) O(k) 使用 groupingBy
分组排序 O(k log k) O(k) k 为组内唯一元素数
交叉分析 O(n*m) O(min(n,m)) m 为组数
总体 O(n + k log k + n*m) O(n) 实际执行中 n*m 通常较小

3. Kotlin 集合 API 的高级应用

groupingBy() 方法解析

groupingBy() 是 Kotlin 标准库提供的扩展函数,用于高效的聚合统计:

// 传统方式(多次遍历,效率较低)
val frequency = mutableMapOf<String, Int>()
items.forEach { item ->
    frequency[item] = frequency.getOrDefault(item, 0) + 1
}

// Kotlin 方式(单次遍历,效率高)
val frequency = items.groupingBy { it }.eachCount()

性能对比:

  • 传统方式: O(n) 时间复杂度,但每次操作都需要 map 查找
  • groupingBy: O(n) 时间复杂度,内部优化了哈希查找,实际性能更优
Set 交集运算优化
// 多组交集计算
val intersection = groups.map { it.items.toSet() }
    .reduce { acc, set -> acc.intersect(set) }

优化策略:

  • 先计算所有组的 Set(去重)
  • 使用 reduce 逐步计算交集
  • 每次交集操作后,结果集变小,后续计算更快

4. 内存优化策略

延迟计算(Lazy Evaluation)

对于大规模数据,可以考虑使用序列(Sequence)进行延迟计算:

val globalUnique = groups.asSequence()
    .flatMap { it.items.asSequence() }
    .distinct()
    .toSet()

优势:

  • 只在需要时才计算
  • 减少中间集合的创建
  • 适用于数据流处理场景
数据结构的空间效率
  • Set vs List: Set 额外存储哈希值,但提供 O(1) 查找
  • Map vs 嵌套 List: Map 虽然占用更多空间,但查找效率高

完整实现代码

Kotlin 核心引擎

/**
 * 数组去重与分组统计入口
 * @param inputData 形如 "GROUP-A:apple,banana,apple,orange|GROUP-B:apple,grape,banana"
 */
@JsExport
fun arrayDeduplicationAnalyzer(inputData: String): String {
    val sanitized = inputData.trim()
    if (sanitized.isEmpty()) {
        return "❌ 输入为空,请按 GROUP-A:apple,banana,apple,orange|GROUP-B:apple,grape 格式提供数据"
    }
    
    val groups = parseArrayGroups(sanitized)
    if (groups.isEmpty()) {
        return "❌ 未解析到任何数据组,请检查格式"
    }
    
    val builder = StringBuilder()
    builder.appendLine("🔢 数组去重与分组统计报告")
    builder.appendLine("━━━━━━━━━━━━━━━━━━━━━━━━━━")
    builder.appendLine("数据组数量: ${groups.size}")
    builder.appendLine("")
    
    // 全局统计:使用 Set 去重,Map 统计频次
    val allItems = groups.flatMap { it.items }
    val globalUnique = allItems.toSet()
    val globalFrequency = allItems.groupingBy { it }.eachCount()
    
    builder.appendLine("===== 全局统计 =====")
    builder.appendLine("总元素数: ${allItems.size}")
    builder.appendLine("去重后元素数: ${globalUnique.size}")
    builder.appendLine("重复率: ${((1.0 - globalUnique.size.toDouble() / allItems.size) * 100).roundToInt()}%")
    builder.appendLine("")
    
    // 分组详细分析
    builder.appendLine("===== 分组详情 =====")
    groups.forEach { group ->
        val uniqueSet = group.items.toSet()
        val frequency = group.items.groupingBy { it }.eachCount()
        val sortedByFreq = frequency.toList().sortedByDescending { it.second }
        
        builder.appendLine("【${group.name}】")
        builder.appendLine("  原始元素数: ${group.items.size}")
        builder.appendLine("  去重后元素数: ${uniqueSet.size}")
        builder.appendLine("  去重列表: ${uniqueSet.sorted().joinToString(", ")}")
        builder.appendLine("  元素频次统计:")
        sortedByFreq.forEach { (item, count) ->
            val bar = "█".repeat((count * 10 / group.items.size).coerceAtMost(10))
            builder.appendLine("    $item: $count$bar")
        }
        builder.appendLine("")
    }
    
    // 交叉分析:集合交集运算
    if (groups.size > 1) {
        val intersection = groups.map { it.items.toSet() }
            .reduce { acc, set -> acc.intersect(set) }
        
        if (intersection.isNotEmpty()) {
            builder.appendLine("===== 交叉分析 =====")
            builder.appendLine("所有组共有元素: ${intersection.sorted().joinToString(", ")}")
            builder.appendLine("共 ${intersection.size} 个")
        }
    }
    
    return builder.toString().trim()
}

private data class ArrayGroup(
    val name: String,
    val items: List<String>
)

private fun parseArrayGroups(raw: String): List<ArrayGroup> {
    val result = mutableListOf<ArrayGroup>()
    val parts = raw.split("|", ";", "\n").filter { it.isNotBlank() }
    
    for (part in parts) {
        val trimmed = part.trim()
        val colonIndex = trimmed.indexOf(':')
        if (colonIndex <= 0) continue
        
        val name = trimmed.substring(0, colonIndex).trim()
        val itemsPart = trimmed.substring(colonIndex + 1).trim()
        
        val items = itemsPart.split(",")
            .map { it.trim() }
            .filter { it.isNotEmpty() }
        
        if (name.isNotEmpty() && items.isNotEmpty()) {
            result += ArrayGroup(name = name, items = items)
        }
    }
    return result
}

JavaScript 桥接层

import { arrayDeduplicationAnalyzer } from './hellokjs.js';

export function runArrayDeduplication(payload) {
  const normalized = typeof payload === 'string' ? payload.trim() : '';
  if (!normalized) {
    return '⚠️ 输入为空,请提供 GROUP-A:item1,item2 形式的数据';
  }
  try {
    const report = arrayDeduplicationAnalyzer(normalized);
    console.info('[array-dedup] success', report.split('\n')[0]);
    return report;
  } catch (error) {
    console.error('[array-dedup] failed', error);
    return `❌ 执行失败: ${error?.message ?? error}`;
  }
}

ArkTS UI 实现

import { arrayDeduplicationAnalyzer } from './hellokjs';

@Component
struct ArrayDeduplicationPanel {
  @State inputData: string = 'GROUP-A:apple,banana,apple,orange|GROUP-B:apple,grape,banana,apple,grape|GROUP-C:apple,orange,grape';
  @State result: string = '';
  @State loading: boolean = false;

  execute() {
    this.loading = true;
    setTimeout(() => {
      this.result = arrayDeduplicationAnalyzer(this.inputData);
      this.loading = false;
    }, 100);
  }
}

算法优化与最佳实践

1. 性能优化技巧

预分配容量

对于已知大小的集合,可以预分配容量以减少扩容开销:

val frequency = mutableMapOf<String, Int>(groups.flatMap { it.items }.size)
使用 Sequence 处理大数据

当数据量很大时,使用 Sequence 可以显著减少内存占用:

val globalUnique = groups.asSequence()
    .flatMap { it.items.asSequence() }
    .distinct()
    .toSet()

2. 边界情况处理

  • 空输入: 返回友好的错误提示
  • 单元素组: 优化显示格式
  • 超大集合: 考虑分页或限制输出

3. 扩展性设计

当前实现支持多种分隔符(|, ;, \n),便于不同的输入场景。未来可以扩展支持:

  • JSON 格式输入
  • 文件导入
  • 流式处理

应用场景

1. 数据清洗

在大数据处理中,经常需要对重复数据进行清洗,本算法提供了高效的去重和统计能力。

2. 用户行为分析

分析多组用户的行为数据,找出共同特征和差异点。

3. 日志分析

对多组日志数据进行去重和频次统计,找出高频事件。

4. 电商数据分析

分析不同商品类别的购买记录,找出热门商品和交叉销售机会。

KMP 与 OpenHarmony 集成策略

1. 跨平台代码共享

  • 业务逻辑: 100% 由 Kotlin 实现,可在多个平台复用
  • UI 层: 使用 ArkTS 实现原生体验
  • 桥接层: JavaScript 提供类型安全的互操作

2. 性能优化

  • Kotlin/JS 编译优化:Tree-shaking 移除未使用代码
  • ArkTS 渲染优化:虚拟列表支持大数据展示
  • 异步处理:避免阻塞 UI 线程

3. 类型安全

通过 TypeScript 定义文件(.d.ts),ArkTS 可以获得完整的类型提示,减少运行时错误。

总结

本文深入探讨了数组去重与分组统计算法的高级实现,展示了如何利用 Kotlin 的集合 API 和哈希表数据结构实现高效的数据处理。通过 KMP 与 OpenHarmony 的协同,我们构建了一个跨平台的解决方案,既保证了代码复用,又提供了原生级的用户体验。

关键要点:

  1. 算法设计: 合理选择数据结构(Set、Map)可以显著提升性能
  2. API 选择: Kotlin 的 groupingBy() 等扩展函数提供了简洁高效的实现
  3. 跨平台架构: KMP 实现了业务逻辑的代码复用,ArkTS 提供了原生 UI 体验
  4. 性能优化: 通过预分配、序列化等技术可以进一步优化性能

这个案例不仅展示了算法的实现,更重要的是展示了如何将理论知识转化为实际可用的跨平台应用。***

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐