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

如何用Newtonsoft Json的MergeArrayHandling.Merge实现指定数组合并

自定义JSON数组合并(基于属性匹配)

首先可以明确:默认的MergeArrayHandling.Merge无法直接实现你想要的效果,因为它是按数组的位置索引来合并元素,而不是根据对象的特定属性(比如name或first)来匹配。你之前尝试的代码会按索引合并外层数组的元素,对于innerArray也是按索引合并,这样会丢失原数组中first=2的元素,或者覆盖成新的first=3的元素,不符合你的需求。

要实现你期望的合并逻辑(外层按name匹配,内层按first匹配更新、新增元素),需要手动处理合并逻辑,而不是依赖默认的Merge方法。下面是具体的实现方案:

实现步骤与代码示例

1. 核心思路

  • 把外层数组转换为以name为键的字典,快速匹配相同名称的对象;
  • 对每个匹配到的对象,再把innerArray转换为以first为键的字典,实现按first匹配更新second值,新增不存在的元素;
  • 最后将字典转换回数组,并保持有序。

2. 完整代码

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

class Program
{
    static void Main()
    {
        // 解析原始JSON数组
        JArray o1 = JArray.Parse(@"[
            {""name"": ""a"", ""innerArray"": [{""first"": 1, ""second"": 1}, {""first"": 2, ""second"": 2}]},
            {""name"": ""b"", ""innerArray"": [{""first"": 1, ""second"": 1}, {""first"": 2, ""second"": 2}]}
        ]");

        JArray o2 = JArray.Parse(@"[
            {""name"": ""a"", ""innerArray"": [{""first"": 1, ""second"": 11}, {""first"": 3, ""second"": 22}]},
            {""name"": ""c"", ""innerArray"": [{""first"": 1, ""second"": 1}, {""first"": 2, ""second"": 2}]}
        ]");

        // 合并外层数组
        var mergedResult = MergeOuterArrays(o1, o2);

        // 输出格式化后的JSON
        Console.WriteLine(mergedResult.ToString(Formatting.Indented));
    }

    private static JArray MergeOuterArrays(JArray array1, JArray array2)
    {
        // 将外层数组转为以name为键的字典
        var outerDict = array1.ToDictionary(
            item => (string)item["name"],
            item => (JObject)item.DeepClone() // 深克隆避免修改原数组
        );

        foreach (JObject item in array2)
        {
            string name = (string)item["name"];
            if (outerDict.ContainsKey(name))
            {
                // 合并当前name对应的innerArray
                var inner1 = (JArray)outerDict[name]["innerArray"];
                var inner2 = (JArray)item["innerArray"];
                outerDict[name]["innerArray"] = MergeInnerArrays(inner1, inner2);
            }
            else
            {
                // 添加新的对象到结果中
                outerDict[name] = (JObject)item.DeepClone();
            }
        }

        // 按name排序后转为JArray,保证输出顺序和期望一致
        return new JArray(outerDict.OrderBy(kv => kv.Key).Select(kv => kv.Value));
    }

    private static JArray MergeInnerArrays(JArray inner1, JArray inner2)
    {
        // 将innerArray转为以first为键的字典
        var innerDict = inner1.ToDictionary(
            item => (int)item["first"],
            item => (JObject)item.DeepClone()
        );

        foreach (JObject item in inner2)
        {
            int firstKey = (int)item["first"];
            if (innerDict.ContainsKey(firstKey))
            {
                // 更新second值(新值覆盖旧值)
                innerDict[firstKey]["second"] = item["second"];
            }
            else
            {
                // 添加新的元素
                innerDict[firstKey] = (JObject)item.DeepClone();
            }
        }

        // 按first排序后转为JArray
        return new JArray(innerDict.OrderBy(kv => kv.Key).Select(kv => kv.Value));
    }
}

3. 代码说明

  • 使用DeepClone()是为了避免修改原始的JArray对象,保证原数据的完整性;
  • 外层和内层分别通过name和first作为唯一标识,确保匹配正确的元素;
  • 最后通过OrderBy保证输出的数组顺序和你期望的一致(a→b→c,innerArray按first升序)。

关于自定义合并匹配索引的说明

Newtonsoft.Json的默认MergeArrayHandling系列选项,都是基于数组的位置索引来处理合并的,没有内置的方式让你自定义“按对象属性作为匹配索引”。如果需要这种基于业务标识的合并,只能通过手动转换字典的方式实现,或者自定义JsonConverter来扩展合并逻辑,但前者更直观易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:32:09