在C#中查找JSON数组中的重复对象并统计出现次数
解决C#中大型JSON数组重复对象统计的问题
嘿,作为C#新手碰到这个需求完全正常,我来给你捋清楚解决思路和具体实现步骤~
核心思路拆解
要完成这个任务,我们需要三步:
- 把JSON字符串转换成C#的强类型对象(方便操作,比硬解析字符串靠谱多了)
- 基于对象的所有属性进行分组,统计每组的出现次数
- 把分组后的结果转换成你需要的输出格式,再序列化回JSON
第一步:定义匹配JSON结构的C#实体类
首先我们要创建和JSON结构对应的类,这样反序列化后能直接用对象操作:
// 对应数组里的单个数据对象 public class DataItem { public string date { get; set; } public string someID { get; set; } public string someType1 { get; set; } public string someType2 { get; set; } } // 对应最外层的原始JSON结构 public class RootObject { public List<DataItem> data { get; set; } } // 对应最终输出的单条结果(继承DataItem,新增统计属性) public class ResultItem : DataItem { public int objCount { get; set; } } // 对应最终输出的外层结构 public class ResultRoot { public List<ResultItem> result { get; set; } }
第二步:反序列化JSON + 分组统计
这里我们用**Json.NET(Newtonsoft.Json)**来处理JSON(这是C#里最常用的JSON库,新手可以先从这个入手;如果用的是.NET 5+,也可以用自带的System.Text.Json,用法类似)。
首先你需要通过NuGet安装Newtonsoft.Json包,然后写代码:
using Newtonsoft.Json; using System.Linq; // 你的原始JSON字符串 string originalJson = @"{""data"": [ { ""date"": ""20220101"", ""someID"": ""ID1"", ""someType1"": ""SRVC"", ""someType2"": ""SEND"" }, { ""date"": ""20220101"", ""someID"": ""ID1"", ""someType1"": ""SRVC"", ""someType2"": ""SEND"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""RECV"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""RECV"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""RECV"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""SEND"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""SEND"" }, { ""date"": ""20220101"", ""someID"": ""ID2"", ""someType1"": ""SRVC"", ""someType2"": ""SEND"" } ] }"; // 1. 把JSON字符串反序列化成C#对象 var root = JsonConvert.DeserializeObject<RootObject>(originalJson); // 2. 用LINQ分组统计:以对象的所有属性作为分组键,自动归类重复对象 var groupedItems = root.data .GroupBy(item => new { item.date, item.someID, item.someType1, item.someType2 }) .Select(group => new ResultItem { date = group.Key.date, someID = group.Key.someID, someType1 = group.Key.someType1, someType2 = group.Key.someType2, objCount = group.Count() }) .ToList(); // 3. 组装成你需要的输出结构 var resultRoot = new ResultRoot { result = groupedItems }; // 4. 把结果序列化回格式化后的JSON字符串 string outputJson = JsonConvert.SerializeObject(resultRoot, Formatting.Indented); Console.WriteLine(outputJson);
关键细节说明
- 为什么用匿名类型作为分组键? 匿名类型的
Equals和GetHashCode方法会自动基于所有属性的值生成,只要两个对象的四个属性完全相同,就会被分到同一组,完美匹配我们判断"重复对象"的需求。 - 超大型数组的优化方案:如果你的JSON数组特别大(比如几十万条以上),LINQ的
GroupBy可能会占用较多内存。这时候可以手动用Dictionary来统计,内存占用更可控:
var countDict = new Dictionary<object, int>(); foreach (var item in root.data) { var key = new { item.date, item.someID, item.someType1, item.someType2 }; if (countDict.ContainsKey(key)) countDict[key]++; else countDict[key] = 1; } // 把字典转换成ResultItem列表 var resultItems = countDict.Select(kv => new ResultItem { date = kv.Key.date, someID = kv.Key.someID, someType1 = kv.Key.someType1, someType2 = kv.Key.someType2, objCount = kv.Value }).ToList();
.NET 5+ 自带System.Text.Json的替代方案
如果你用的是较新的.NET版本,不想额外装NuGet包,可以用自带的System.Text.Json,写法类似:
using System.Text.Json; // 反序列化 var root = JsonSerializer.Deserialize<RootObject>(originalJson); // 分组统计(逻辑和之前完全一致) var groupedItems = root.data .GroupBy(item => new { item.date, item.someID, item.someType1, item.someType2 }) .Select(group => new ResultItem { date = group.Key.date, someID = group.Key.someID, someType1 = group.Key.someType1, someType2 = group.Key.someType2, objCount = group.Count() }) .ToList(); // 序列化回格式化后的JSON var options = new JsonSerializerOptions { WriteIndented = true }; string outputJson = JsonSerializer.Serialize(new ResultRoot { result = groupedItems }, options); Console.WriteLine(outputJson);
运行后就能得到你想要的输出结果啦!如果有其他细节问题,随时问~
内容的提问来源于stack exchange,提问作者Jonald Monday
相关产品推荐
相关产品推荐

