Kotlin如何合并列表同类项、聚合字段值并收集关联设备列表
Kotlin实现JSON分类聚合方案
原始输入JSON结构
{ "status": [ { "conferencing": { "nrOfRxBytes": 1142294, "nrOfTxBytes": 368502, "CategoryActiveTime": 9625, "Active": true }, "social_media": { "nrOfRxBytes": 163156131, "nrOfTxBytes": 1438337, "CategoryActiveTime": 10406, "Active": true }, "media_streaming": { "nrOfRxBytes": 5065342, "nrOfTxBytes": 312250, "CategoryActiveTime": 213, "Active": false }, "Device": "BE:A0:FE:74:39:C1" }, { "conferencing": { "nrOfRxBytes": 58534, "nrOfTxBytes": 24615, "CategoryActiveTime": 10343, "Active": true }, "social_media": { "nrOfRxBytes": 5618, "nrOfTxBytes": 2731, "CategoryActiveTime": 14308, "Active": true }, "media_streaming": { "nrOfRxBytes": 747, "nrOfTxBytes": 397, "CategoryActiveTime": 448, "Active": false }, "education": { "nrOfRxBytes": 404, "nrOfTxBytes": 260, "CategoryActiveTime": 419, "Active": false }, "Device": "AC:12:03:EC:9B:D1" } ] }
需求说明
需要对education/conferencing/social_media/media_streaming等同名分类做合并处理:
- 对分类下的
nrOfRxBytes/nrOfTxBytes/CategoryActiveTime数值字段做累加聚合 - 收集每个分类关联的所有
Device值组成列表 Active字段只要分类下有任意一个设备的该分类为活跃状态即保留为true
期望输出结构示例:
[{ "name":"conferencing", "nrOfRxBytes": 1200828, "nrOfTxBytes": 393117, "CategoryActiveTime": 19968, "Active": true, "Device": ["AC:12:03:EC:9B:D1","BE:A0:FE:74:39:C1"] },...]
现有待修正代码
原有数据类定义
@Parcelize data class ServicesIdCategory( var name: String = "", val nrOfRxBytes: Int = 0, val nrOfTxBytes: Int = 0, val CategoryActiveTime: Int = 0, val Active: Boolean = false, var Device: String = "" ) : Parcelable
原有解析方法
fun getLiveServicesId(response: JSONArray): Array<ServicesIdCategory> { val array = mutableListOf<DeviceServicesId>() var categories = mutableListOf<ServicesIdCategory>() var category = ServicesIdCategory() val gson = Gson() for (i in 0 until response.length()) { val obj = response.getJSONObject(i) val namesArr = obj.names() if (namesArr != null) { for (j in 0 until namesArr.length()) { if (namesArr[j].toString() != "Device") { val categoryJson = obj.optString( namesArr[j].toString(), "" ) try { category = gson.fromJson(categoryJson, ServicesIdCategory::class.java) category.name = namesArr[j].toString() } catch (e: JsonSyntaxException) { } } category.Device = obj.optString("Device") categories.add(category) } } val deviceServiceId = gson.fromJson(obj.toString(), DeviceServicesId::class.java) deviceServiceId.servicesIdCategory = categories.toTypedArray() array.add(deviceServiceId) } return categories.toTypedArray() }
现有代码未实现同类项合并、数值聚合、设备列表收集逻辑。
正确实现步骤
1. 修正数据类定义
首先调整字段类型适配需求:
- 数值字段改为
Long避免大数值溢出 Device字段改为List<String>存储关联设备列表
@Parcelize data class ServicesIdCategory( val name: String = "", val nrOfRxBytes: Long = 0L, val nrOfTxBytes: Long = 0L, val CategoryActiveTime: Long = 0L, val Active: Boolean = false, val Device: List<String> = emptyList() ) : Parcelable // 用于解析单设备下单个分类的原始结构 private data class RawCategoryMetric( val nrOfRxBytes: Long = 0L, val nrOfTxBytes: Long = 0L, val CategoryActiveTime: Long = 0L, val Active: Boolean = false )
2. 实现解析+聚合逻辑
利用Kotlin标准库的groupBy做分类聚合,避免手动维护映射表,逻辑更简洁:
import org.json.JSONArray import org.json.JSONObject import com.google.gson.Gson fun getLiveServicesId(statusArray: JSONArray): Array<ServicesIdCategory> { val gson = Gson() // 第一步:扁平化所有(分类名、指标、设备MAC)三元组 val flatCategoryList = mutableListOf<Triple<String, RawCategoryMetric, String>>() for (i in 0 until statusArray.length()) { val deviceObj = statusArray.getJSONObject(i) val deviceMac = deviceObj.optString("Device") val keys = deviceObj.keys() while (keys.hasNext()) { val key = keys.next() // 跳过Device字段,其余都是分类项 if (key == "Device") continue runCatching { val metric = gson.fromJson( deviceObj.getJSONObject(key).toString(), RawCategoryMetric::class.java ) flatCategoryList.add(Triple(key, metric, deviceMac)) } } } // 第二步:按分类名分组聚合 return flatCategoryList .groupBy { it.first } // 按分类名分组 .map { (categoryName, groupItems) -> // 累加数值字段 val totalRx = groupItems.sumOf { it.second.nrOfRxBytes } val totalTx = groupItems.sumOf { it.second.nrOfTxBytes } val totalActiveTime = groupItems.sumOf { it.second.CategoryActiveTime } // 只要任意一个设备该分类活跃,就标记为true val isActive = groupItems.any { it.second.Active } // 收集关联设备并去重 val deviceList = groupItems.map { it.third }.distinct() ServicesIdCategory( name = categoryName, nrOfRxBytes = totalRx, nrOfTxBytes = totalTx, CategoryActiveTime = totalActiveTime, Active = isActive, Device = deviceList ) } .toTypedArray() }
实现说明
- 用
runCatching包裹单分类解析逻辑,避免单个字段格式错误导致整个解析流程中断 - 设备列表加
distinct()做去重,避免同一设备重复上报同分类时出现重复MAC - 数值字段统一用
Long类型,避免流量值过大出现Int溢出问题 Active字段采用any聚合,只要有一个设备该分类处于活跃状态,合并后的分类就标记为活跃
内容的提问来源于stack exchange,提问作者Khmaies
相关产品推荐
相关产品推荐

