You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于公共键高效合并两个JSON字符串?

基于公共键合并两个JSON数组的高效Jackson实现方案

问题背景

现有两个JSON数组字符串,结构如下:

JSON-1:

[
    {
        "title": "ABC",
        "edition": 7,
        "year": 2011
    },
    {
        "title": "DEF",
        "edition": 2,
        "year": 2012
    },
    {
        "title": "XYZ",
        "edition": 3,
        "year": 2013
    }
]

JSON-2:

[
    {
        "title": "ABC",
        "price": "20"
    },
    {
        "title": "DEF",
        "price": "20"
    },
    {
        "title": "XYZ",
        "price": "20"
    }
]

需基于公共键title合并两个数组,将JSON-2的属性合并到JSON-1中,最终得到包含所有属性的JSON数组,要求:

  • 不使用实体/模型类
  • 禁止使用Gson库
  • 以最少循环和对象创建实现

尝试过两种Jackson方案但遇到问题:

  1. 使用List<JSONObject> listObj = objectMapper.readValue(jsonOneString, new TypeReference<List<JSONObject>>(){});时触发未知属性异常
  2. 使用JsonNode node = objectMapper.readTree(jsonOneString);但无法继续完成合并操作

已写出title匹配的判断逻辑:

if (json1elem.get("title")!=null 
        && json2elem.get("title")!=null 
            && json1elem.get("title").equals(json2elem.get("title"))) {
    // 合并逻辑待实现
}

高效实现方案

核心思路是先将第二个JSON数组转换为title到对应节点的映射表,再遍历第一个数组直接通过映射表匹配合并,避免嵌套循环,将时间复杂度从O(n*m)优化为O(n+m),同时使用Jackson原生的可变节点ObjectNode完成属性合并。

完整代码实现

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class JsonArrayMerge {
    public static void main(String[] args) throws Exception {
        // 输入的两个JSON字符串
        String jsonStr1 = "[{\"title\":\"ABC\",\"edition\":7,\"year\":2011},{\"title\":\"DEF\",\"edition\":2,\"year\":2012},{\"title\":\"XYZ\",\"edition\":3,\"year\":2013}]";
        String jsonStr2 = "[{\"title\":\"ABC\",\"price\":\"20\"},{\"title\":\"DEF\",\"price\":\"20\"},{\"title\":\"XYZ\",\"price\":\"20\"}]";

        ObjectMapper objectMapper = new ObjectMapper();
        // 读取两个JSON数组为JsonNode
        JsonNode arrayNode1 = objectMapper.readTree(jsonStr1);
        JsonNode arrayNode2 = objectMapper.readTree(jsonStr2);

        // 构建title到JsonNode的映射表,仅需遍历一次JSON-2
        Map<String, JsonNode> titleNodeMap = new HashMap<>();
        for (JsonNode node : arrayNode2) {
            String title = node.get("title").asText();
            titleNodeMap.put(title, node);
        }

        // 遍历JSON-1的节点,合并对应属性
        Iterator<JsonNode> iterator = arrayNode1.iterator();
        while (iterator.hasNext()) {
            JsonNode currentNode = iterator.next();
            if (currentNode instanceof ObjectNode) {
                ObjectNode mutableNode = (ObjectNode) currentNode;
                String title = currentNode.get("title").asText();
                // 从映射表中获取对应title的JSON-2节点
                JsonNode mergeNode = titleNodeMap.get(title);
                if (mergeNode != null) {
                    // 合并除title外的所有属性
                    mergeNode.fields().forEachRemaining(entry -> {
                        if (!"title".equals(entry.getKey())) {
                            mutableNode.set(entry.getKey(), entry.getValue());
                        }
                    });
                }
            }
        }

        // 输出格式化后的合并结果
        String mergedJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(arrayNode1);
        System.out.println(mergedJson);
    }
}

方案说明

  1. 映射表构建:将JSON-2的节点以title为key存入HashMap,后续匹配时直接O(1)查找,避免嵌套循环的低效。
  2. 可变节点操作:Jackson的JsonNode是不可变的,因此需要将其转为ObjectNode才能修改节点属性,完成合并。
  3. 属性合并逻辑:遍历JSON-2节点的所有字段,跳过重复的title键,将其余属性添加到JSON-1的对应节点中。

解决之前的问题

  • 针对第一种方案的未知属性异常:若坚持使用List<ObjectNode>,可添加配置objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)关闭未知属性校验,但使用readTree更简洁直接。
  • 针对第二种方案无法推进:核心是没有将不可变的JsonNode转为ObjectNode,也未使用映射表优化匹配效率。

内容的提问来源于stack exchange,提问作者New2Java

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:55:23