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

基于动态JSON字段列表在C#中实现数据分组与聚合

C# 动态JSON分组聚合解决方案

针对你需要对动态结构的JSON数组进行类似SQL分组聚合的需求,这里提供基于**Newtonsoft.Json(Json.NET)**的实现方案,该库在处理动态JSON场景下灵活性极强,能满足指定分组字段+聚合函数(SUM/MIN/MAX/COUNT)的需求。

核心实现思路

  1. 解析输入JSON数组为JArray,方便动态访问每个JSON对象的属性
  2. 解析分组字段列表,区分普通分组字段(如col1)和聚合字段(如MAX(col3))
  3. 以普通分组字段的组合值作为分组键,对JSON对象分组
  4. 对每个分组应用对应的聚合函数计算结果
  5. 将分组键与聚合结果组合成新的JSON对象,最终输出聚合后的JSON数组

完整代码示例

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

public class JsonGroupAggregator
{
    public static string AggregateJson(string inputJson, List<string> groupFields)
    {
        // 解析输入JSON数组
        JArray inputArray = JArray.Parse(inputJson);
        if (!inputArray.Any()) return "[]";

        // 拆分分组字段和聚合字段
        var groupingKeys = new List<string>();
        var aggregations = new List<(string FuncName, string FieldName)>();

        foreach (var field in groupFields)
        {
            if (field.StartsWith("SUM(") || field.StartsWith("MIN(") || field.StartsWith("MAX(") || field.StartsWith("COUNT("))
            {
                // 提取聚合函数和目标字段
                var funcEndIndex = field.IndexOf('(');
                var fieldEndIndex = field.IndexOf(')');
                string funcName = field.Substring(0, funcEndIndex);
                string fieldName = field.Substring(funcEndIndex + 1, fieldEndIndex - funcEndIndex - 1);
                aggregations.Add((funcName, fieldName));
            }
            else
            {
                groupingKeys.Add(field);
            }
        }

        // 分组逻辑:以分组字段的键值对组合作为分组依据
        var groupedData = inputArray.GroupBy(item =>
        {
            var keyValues = groupingKeys.ToDictionary(key => key, key => item[key]);
            return new Dictionary<string, JToken>(keyValues);
        }, new DictionaryComparer());

        // 生成聚合结果
        var resultArray = new JArray();
        foreach (var group in groupedData)
        {
            var resultObj = new JObject();

            // 添加分组字段到结果
            foreach (var key in groupingKeys)
            {
                resultObj[key] = group.Key[key];
            }

            // 处理聚合函数
            foreach (var (funcName, fieldName) in aggregations)
            {
                var fieldValues = group.Select(item => item[fieldName]);
                JToken aggregatedValue = funcName switch
                {
                    "SUM" => new JValue(fieldValues.Sum(v => v.ToObject<decimal>())),
                    "MIN" => fieldValues.Min(),
                    "MAX" => fieldValues.Max(),
                    "COUNT" => new JValue(group.Count()),
                    _ => throw new NotSupportedException($"不支持的聚合函数:{funcName}")
                };
                resultObj[$"{funcName}({fieldName})"] = aggregatedValue;
            }

            resultArray.Add(resultObj);
        }

        return resultArray.ToString(Formatting.Indented);
    }

    // 自定义字典比较器,用于GroupBy的分组键比较
    private class DictionaryComparer : IEqualityComparer<Dictionary<string, JToken>>
    {
        public bool Equals(Dictionary<string, JToken> x, Dictionary<string, JToken> y)
        {
            if (x.Count != y.Count) return false;
            foreach (var pair in x)
            {
                if (!y.ContainsKey(pair.Key) || !JToken.DeepEquals(pair.Value, y[pair.Key]))
                {
                    return false;
                }
            }
            return true;
        }

        public int GetHashCode(Dictionary<string, JToken> obj)
        {
            int hash = 17;
            foreach (var pair in obj.OrderBy(kv => kv.Key))
            {
                hash = hash * 31 + pair.Key.GetHashCode();
                hash = hash * 31 + (pair.Value?.GetHashCode() ?? 0);
            }
            return hash;
        }
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        string inputJson = @"[{""col1"": ""a1"",""col2"": ""b1"",""col3"": 10}, {""col1"": ""a1"",""col2"": ""b1"",""col3"": 11}, {""col1"": ""a2"",""col2"": ""b2"",""col3"": 5}, {""col1"": ""a2"",""col2"": ""b2"",""col3"": 7}]";
        List<string> groupFields = new List<string> { "col1", "col2", "MAX(col3)", "SUM(col3)" };

        string result = JsonGroupAggregator.AggregateJson(inputJson, groupFields);
        Console.WriteLine(result);
    }
}

代码说明

  • 分组键处理:通过自定义DictionaryComparer确保不同JSON对象的分组字段值完全一致时被分到同一组
  • 聚合函数支持:当前实现了SUM(按decimal计算,兼容整数和浮点数)、MIN、MAX、COUNT四种常用聚合函数,可根据需求扩展
  • 动态适配:无需提前定义实体类,完全基于JSON的动态结构处理,适配任意字段组合
  • 结果格式:输出的JSON保持与输入一致的字段命名规则,聚合结果字段名保留Func(Field)格式(如MAX(col3))

注意事项

  • 确保输入JSON中的聚合字段为数值类型(SUM/MIN/MAX),否则会抛出类型转换异常
  • 如果需要支持更多聚合函数(如AVG),只需在aggregatedValue的switch语句中添加对应逻辑
  • 若使用System.Text.Json,可将JArray/JObject替换为JsonElement,核心逻辑保持一致,只是动态属性访问方式略有不同

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:25:13