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

C#中合并含内部数组的JSON数组,实现匹配键值覆盖

自定义JSON数组合并:按指定键匹配替换内层项

问题场景

现有两个嵌套结构的JSON数组:

第一个JSON数组

[{"name":"a","innerArray":[{"first":1,"second":1},{"first":2,"second":2}]},{"name":"b","innerArray":[{"first":1,"second":1},{"first":2,"second":2}]}]

第二个JSON数组

[{"name":"a","innerArray":[{"first":1,"second":11},{"first":3,"second":22}]},{"name":"c","innerArray":[{"first":1,"second":1},{"first":2,"second":2}]}]

期望合并规则:

  • 外层数组按name字段匹配,存在则合并内部数组,不存在则新增
  • 内部innerArray按first字段匹配:相同first值的项用第二个数组的内容覆盖,第二个数组里不存在的first值保留原项,新增第二个数组里独有的项

使用Json.NET默认的Merge方法(设置MergeArrayHandling.Union)无法实现该逻辑,因为它会直接替换整个内部数组,而非按指定键匹配替换。

解决方案:自定义合并逻辑

通过手动遍历、字典映射的方式实现精准匹配合并,代码示例如下:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // 原始JSON字符串
        string json1 = @"[{""name"":""a"",""innerArray"":[{""first"":1,""second"":1},{""first"":2,""second"":2}]},{""name"":""b"",""innerArray"":[{""first"":1,""second"":1},{""first"":2,""second"":2}]}]";
        string json2 = @"[{""name"":""a"",""innerArray"":[{""first"":1,""second"":11},{""first"":3,""second"":22}]},{""name"":""c"",""innerArray"":[{""first"":1,""second"":1},{""first"":2,""second"":2}]}]";

        // 解析为JArray
        JArray arr1 = JArray.Parse(json1);
        JArray arr2 = JArray.Parse(json2);

        // 外层转换为name为键的字典,方便匹配
        var dict1 = arr1.ToDictionary(item => item["name"].ToString(), item => item);
        var dict2 = arr2.ToDictionary(item => item["name"].ToString(), item => item);

        foreach (var kvp in dict2)
        {
            string name = kvp.Key;
            JObject targetObj = kvp.Value as JObject;

            if (dict1.ContainsKey(name))
            {
                // 存在相同name,合并innerArray
                JObject sourceObj = dict1[name] as JObject;
                JArray sourceInner = sourceObj["innerArray"] as JArray;
                JArray targetInner = targetObj["innerArray"] as JArray;

                // 把内层数组转为first为键的字典
                var innerDict = sourceInner.ToDictionary(item => item["first"].Value<int>(), item => item);

                // 遍历目标内层数组,替换或新增项
                foreach (JObject innerItem in targetInner)
                {
                    int first = innerItem["first"].Value<int>();
                    innerDict[first] = innerItem; // 覆盖已有项,新增不存在的项
                }

                // 转换回JArray,保持有序
                var mergedInner = new JArray(innerDict.OrderBy(k => k.Key).Select(k => k.Value));
                sourceObj["innerArray"] = mergedInner;
            }
            else
            {
                // 不存在则直接添加
                dict1.Add(name, targetObj);
            }
        }

        // 转换回JArray并输出
        JArray mergedResult = new JArray(dict1.Values.OrderBy(item => item["name"].ToString()));
        Console.WriteLine(mergedResult.ToString(Formatting.Indented));
    }
}

输出结果

运行上述代码后,输出的合并结果与预期一致:

[
  {
    "name": "a",
    "innerArray": [
      {
        "first": 1,
        "second": 11
      },
      {
        "first": 2,
        "second": 2
      },
      {
        "first": 3,
        "second": 22
      }
    ]
  },
  {
    "name": "b",
    "innerArray": [
      {
        "first": 1,
        "second": 1
      },
      {
        "first": 2,
        "second": 2
      }
    ]
  },
  {
    "name": "c",
    "innerArray": [
      {
        "first": 1,
        "second": 1
      },
      {
        "first": 2,
        "second": 2
      }
    ]
  }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 08:55:17