C#中使用Newtonsoft多条件筛选JSON并计算平均值问题
在C#中用Newtonsoft处理JSON数据的正确方案
问题分析
你遇到的核心问题是Newtonsoft JSONPath对复杂多条件组合的支持有限,且用Intersect合并筛选结果的思路不符合数据层级逻辑(区域和item是嵌套关系,而非平行集合),导致区域筛选空值、无法提取value。
修正方案:用LINQ to JSON分步处理
相比JSONPath,LINQ to JSON(基于JObject/JArray)更灵活,能清晰实现多层筛选逻辑,步骤如下:
1. 完整代码示例
先确保引用Newtonsoft.Json.Linq命名空间,然后按以下逻辑编写代码:
using Newtonsoft.Json.Linq; using System; using System.Linq; class Program { static void Main() { // 替换为你的实际JSON字符串 string jsonStr = @" { ""regions"": [ { ""area"": 1, ""items"": [ { ""value"": 0.3, ""numbers"": [2, 2, 1, 1] }, { ""value"": 0.5, ""numbers"": [-2, 3, 0.5, 1] }, { ""value"": 0.2, ""numbers"": [1, 2, 1, 1] } ] }, { ""area"": 2, ""items"": [ { ""value"": 0.6, ""numbers"": [2, 0, 1, 1] } ] } ] }"; // 解析JSON JObject root = JObject.Parse(jsonStr); // 步骤1:筛选area=1的区域 var targetRegions = root["regions"]? .Where(region => region["area"]?.Value<int>() == 1) .ToList(); if (!targetRegions.Any()) { Console.WriteLine("未找到area=1的区域"); return; } // 步骤2:提取所有区域下的items,并筛选符合numbers条件的项 var validItems = targetRegions .SelectMany(region => region["items"]?.Children<JObject>() ?? Enumerable.Empty<JObject>()) .Where(item => { var numbers = item["numbers"]?.Values<double>().ToList(); // 先判断numbers数组长度是否足够 if (numbers == null || numbers.Count < 4) return false; // 逐一验证条件 bool cond1 = numbers[0] == 2 || numbers[0] == -2; bool cond2 = numbers[1] > 1; bool cond3 = numbers[2] > 0; bool cond4 = numbers[3] == 1; return cond1 && cond2 && cond3 && cond4; }) .ToList(); // 步骤3:计算value的平均值 if (validItems.Any()) { double averageValue = validItems.Average(item => item["value"]?.Value<double>() ?? 0); Console.WriteLine($"符合条件的items的value平均值:{averageValue}"); // 预期输出0.4 } else { Console.WriteLine("没有符合条件的items"); } } }
2. 方案优势
- 解决区域筛选空值问题:用
Where直接遍历regions数组,判断area字段值,避免JSONPath的语法歧义。 - 支持复杂条件组合:通过LINQ的
Where方法组合多条件,逻辑清晰,不受JSONPath的语法限制。 - 直接提取并计算:从符合条件的
JObject中直接提取value字段,用Average方法计算平均值,无需额外集合合并操作。
关于JSONPath的替代尝试(不推荐)
如果一定要用JSONPath,可结合LINQ分步执行:
- 先提取area=1的区域下的所有items:
var allItemsInArea1 = root.SelectTokens("$..regions[?(@.area == 1)].items[*]"); - 再对这些items应用numbers条件:
var validItems = allItemsInArea1.Where(item => item.SelectToken("numbers[0]").Value<double>() is 2 or -2 && item.SelectToken("numbers[1]").Value<double>() > 1 && item.SelectToken("numbers[2]").Value<double>() > 0 && item.SelectToken("numbers[3]").Value<double>() == 1 );
本质还是依赖LINQ,单纯JSONPath难以实现复杂多条件组合。
总结
优先选择LINQ to JSON方案,它更直观、易调试,能完美覆盖你的多层筛选和计算需求,避免JSONPath的语法局限性。
内容的提问来源于stack exchange,提问作者BezqyczekPL
相关产品推荐
相关产品推荐

