如何快速移除System.Text.Json.Nodes.JsonArray中符合条件的数百元素?
问题描述
如何以最快方式移除System.Text.Json.Nodes.JsonArray中符合特定条件的数百个元素?我有一个包含数百个元素的JsonArray,多数是无效数据,只需要保留符合指定条件的元素。是否能实现类似以下代码的操作?
jsonArray.RemoveAll(e => /* 任意条件 */)
我要最快的解决方案,不局限于JsonArray,也可以用更合适的替代方案。
更新内容:JSON文件示例
[{ "timestamp":"2023-03-13T15:21:24.057Z", "type":"Gateway", "mac":"AC233FC0F654", "gatewayFree":23, "gatewayLoad":0.39000000000000001 }, { "timestamp":"2023-03-13T15:21:24.057Z", "type":"Unknown", "mac":"157007098D2E", "bleNo":0, "bleName":"", "rssi":-67, "rawData":"02011A07FF4C0015020034" }, { "timestamp":"2023-03-13T15:21:24.058Z", "type":"Unknown", "mac":"147D21B57EB9", "bleNo":0, "bleName":"", "rssi":-78, "rawData":"0201060309536B16FF53500004F6400201020304FBE705060708040102FF" }]
方案1:基于JsonArray的过滤实现
JsonArray没有内置RemoveAll方法,但可以通过两种方式实现需求:
新建过滤后的JsonArray(简洁优先)
直接通过LINQ筛选符合条件的元素,创建新数组,代码简洁易维护:
using System.Text.Json.Nodes; // 假设jsonArray为已加载的目标数组 var filteredArray = new JsonArray( jsonArray.Where(node => node["type"]?.GetValue<string>() == "Gateway").ToArray() );
- 优势:代码简洁,避免原地修改的索引错乱问题
- 劣势:会创建新数组,占用少量额外内存(数百级元素可忽略)
原地反向遍历删除(内存优先)
如果需要原地修改、避免额外内存占用,可反向遍历删除元素(正向遍历会因元素移除导致索引偏移):
for (int i = jsonArray.Count - 1; i >= 0; i--) { var node = jsonArray[i]; if (node["type"]?.GetValue<string>() != "Gateway") { jsonArray.RemoveAt(i); } }
- 优势:无额外内存开销
- 劣势:代码稍繁琐,仅适合必须原地修改的场景
方案2:强类型集合过滤(性能最优)
如果JSON结构固定,反序列化为强类型List<T>后过滤是性能最高的方案,强类型操作比动态节点访问更快。
步骤1:定义对应实体类
public class DeviceData { public DateTime Timestamp { get; set; } public string Type { get; set; } public string Mac { get; set; } public int? GatewayFree { get; set; } public double? GatewayLoad { get; set; } public int? BleNo { get; set; } public string BleName { get; set; } public int? Rssi { get; set; } public string RawData { get; set; } }
步骤2:反序列化+过滤
using System.Text.Json; // 从JSON字符串反序列化 var deviceList = JsonSerializer.Deserialize<List<DeviceData>>(jsonString); // 过滤保留符合条件的元素 var filteredList = deviceList.Where(d => d.Type == "Gateway").ToList(); // 如需转回JsonArray var filteredArray = JsonSerializer.SerializeToNode(filteredList) as JsonArray;
- 优势:性能最优,类型安全,代码可读性强
- 劣势:需要提前定义实体类,仅适合结构固定的JSON
方案3:JsonDocument流式处理(内存友好)
如果JSON文件规模远超数百级元素,用JsonDocument流式读取过滤,避免一次性加载整个文档到内存:
using System.Text.Json; using var doc = JsonDocument.Parse(jsonString); var filteredElements = new List<JsonElement>(); foreach (var element in doc.RootElement.EnumerateArray()) { if (element.TryGetProperty("type", out var typeProp) && typeProp.GetString() == "Gateway") { filteredElements.Add(element.Clone()); // 必须Clone,否则文档释放后元素失效 } } // 转回JsonArray或直接序列化输出 var filteredJson = JsonSerializer.Serialize(filteredElements); var filteredArray = JsonSerializer.Deserialize<JsonArray>(filteredJson);
- 优势:内存占用极低,适合超大JSON文件
- 劣势:代码稍复杂,数百级元素场景下没必要使用
性能对比
- 数百级元素:**方案2(强类型过滤)**性能最优,其次是方案1的新建数组,最后是原地删除
- 超大文件:方案3为最优选择
内容的提问来源于stack exchange,提问作者A. Wheatman
相关产品推荐
相关产品推荐

