Java如何实现类似Python pandas的JSON数据groupby分组操作
Java实现动态分组JSON转换方案
Java生态没有pandas封装好的DataFrame开箱即用能力,但用JDK原生Stream聚合 + 通用JSON解析库,就能完全实现你要的效果,而且支持动态指定分组字段,不需要硬编码枚举值。
核心思路
和pandas groupby逻辑完全对齐:
- 先把原始JSON解析为无类型的通用树结构,避免写固定Java实体类,适配字段动态变化的场景
- 按指定的分组字段做聚合,同组内的ID收集为数组,ref、categ这类同组值一致的字段直接保留,丢弃不需要的pagenb字段
- 聚合完成后重新序列化为JSON输出
具体实现
这里用Jackson做JSON处理,是Java生态最通用的JSON库,也是Spring等主流框架的默认JSON组件,稳定性和易用性都适合初学者。
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class JsonGroupConvert { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); // -------------------------- 可动态修改的配置项 -------------------------- String rawJsonInput = """ [ {"ID":"id1","ref":"ref1","categ":"CATEG_A","pagenb":1}, {"ID":"id2","ref":"ref1","categ":"CATEG_A","pagenb":2}, {"ID":"id3","ref":"ref1","categ":"CATEG_B","pagenb":3} ] """; String groupField = "categ"; // 分组依据字段,后续换其他分组字段直接改这个值 String arrayField = "ID"; // 需要收集为数组的字段 List<String> keepCommonFields = List.of("ref", groupField); // 同组内值一致、直接保留的字段 List<String> dropFields = List.of("pagenb"); // 转换后丢弃的字段 // ---------------------------------------------------------------------- // 解析原始JSON数组 ArrayNode rawNodes = (ArrayNode) mapper.readTree(rawJsonInput); List<JsonNode> nodeList = new ArrayList<>(); rawNodes.forEach(nodeList::add); // 按分组字段聚合,等价于df.groupby(groupField) Map<String, List<JsonNode>> groupResult = nodeList.stream() .collect(Collectors.groupingBy(node -> node.get(groupField).asText())); // 组装目标JSON结构 ArrayNode outputArray = mapper.createArrayNode(); for (Map.Entry<String, List<JsonNode>> entry : groupResult.entrySet()) { List<JsonNode> sameGroupNodes = entry.getValue(); ObjectNode outputNode = mapper.createObjectNode(); // 组装收集为数组的字段 ArrayNode collectedArray = mapper.createArrayNode(); sameGroupNodes.forEach(node -> collectedArray.add(node.get(arrayField).asText())); outputNode.set(arrayField, collectedArray); // 组装保留的公共字段(默认取同组第一条数据的值,如果业务上同组字段可能存在不一致,可以在这里加校验逻辑) for (String field : keepCommonFields) { outputNode.set(field, sameGroupNodes.get(0).get(field)); } outputArray.add(outputNode); } // 打印输出最终结果,和你要求的目标格式完全一致 System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(outputArray)); } }
扩展说明
- 所有和字段相关的逻辑都抽成了顶部配置项,不管分组字段从categ换成其他任意字段,还是要调整收集/保留/丢弃的字段,都不需要修改核心聚合逻辑,灵活度和pandas的动态分组能力一致
- 没有绑定固定Java类,用通用JsonNode处理数据,就算后续JSON结构增减字段,核心代码也不需要改动
- 核心聚合逻辑用JDK原生Stream的
groupingBy方法实现,逻辑和pandas的groupby完全一致,有Python基础可以很快理解 - 运行代码前只要引入Jackson的核心包即可,不需要额外依赖其他重型框架
内容的提问来源于stack exchange,提问作者Sarindra Thérèse
相关产品推荐
相关产品推荐

