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

如何实现基于动态自定义条件的通用JSON数组筛选功能

动态筛选JSON数组的两种实现方案

以下两种方案均支持任意数量的筛选条件,兼容字符串、数值、日期类型的比较判断,可直接适配你提到的逗号分隔条件输入格式。


方案1:动态生成JsonPath(实现成本最低)

通过解析输入的条件字符串,直接拼接生成标准JsonPath表达式,利用Newtonsoft.Json内置的JsonPath查询能力实现筛选,无需复杂的逻辑开发。

核心实现代码

using Newtonsoft.Json.Linq;

public static JArray FilterJsonArray(string jsonArrayStr, string conditionString)
{
    var jArray = JArray.Parse(jsonArrayStr);
    if (string.IsNullOrWhiteSpace(conditionString))
        return jArray;

    // 支持的操作符,按长度降序排列,优先匹配长操作符避免拆分错误
    var supportOperators = new List<string> { ">=", "<=", "!=", "=", ">", "<" };
    // 输入的等于号映射为JsonPath标准的双等于号
    var opMap = new Dictionary<string, string> { { "=", "==" } };
    var conditionList = new List<string>();

    foreach (var condItem in conditionString.Split(',', StringSplitOptions.RemoveEmptyEntries))
    {
        var cleanedCond = condItem.Trim();
        var op = supportOperators.First(o => cleanedCond.Contains(o));
        var parts = cleanedCond.Split(new[] { op }, StringSplitOptions.RemoveEmptyEntries);
        var fieldName = parts[0].Trim();
        var rawValue = parts[1].Trim().Trim('"', '\'');

        // 根据值类型生成对应格式的查询值
        string formattedValue;
        if (DateTime.TryParse(rawValue, out DateTime dateValue))
        {
            // 日期统一转成ISO格式避免解析错误
            formattedValue = $"'{dateValue:yyyy-MM-dd HH:mm:ss}'";
        }
        else if (double.TryParse(rawValue, out _))
        {
            // 数值类型不需要加引号
            formattedValue = rawValue;
        }
        else
        {
            // 字符串转义单引号
            formattedValue = $"'{rawValue.Replace("'", "\\'")}'";
        }

        var actualOp = opMap.TryGetValue(op, out var mappedOp) ? mappedOp : op;
        conditionList.Add($"@.{fieldName} {actualOp} {formattedValue}");
    }

    // 拼接完整JsonPath表达式
    var jsonPath = $"$.[?({string.Join(" && ", conditionList)})]";
    return new JArray(jArray.SelectTokens(jsonPath));
}

调用示例

// 单条件筛选EmpID=29
var result1 = FilterJsonArray(员工JSON字符串, "EmpID=\"29\"");

// 多条件筛选Age=23且EmpName=Jhon
var result2 = FilterJsonArray(员工JSON字符串, "Age=\"23\",EmpName=\"Jhon\"");

// 日期类型筛选BirthDate大于1995年5月12日
var result3 = FilterJsonArray(包含生日的JSON字符串, "BirthDate>1995-05-12");

本方案优势:代码量少、适配快,天然支持任意数量条件的组合;劣势为性能略低于LINQ方案,适合调用频率不高的场景。


方案2:动态构建LINQ表达式树(性能更优)

通过动态构建Lambda表达式树实现筛选,编译后的委托执行效率更高,且类型安全,不会出现字符串比较导致的逻辑错误,适合高频调用场景。

核心实现代码

using System.Linq.Expressions;
using Newtonsoft.Json.Linq;

public static List<JObject> FilterJsonArrayWithLinq(string jsonArrayStr, string conditionString)
{
    var jArray = JArray.Parse(jsonArrayStr).OfType<JObject>().ToList();
    if (string.IsNullOrWhiteSpace(conditionString))
        return jArray;

    var supportOperators = new List<string> { ">=", "<=", "!=", "=", ">", "<" };
    // 定义Lambda参数 x => ...
    var parameter = Expression.Parameter(typeof(JObject), "x");
    // 初始条件为true
    Expression combinedCondition = Expression.Constant(true);

    foreach (var condItem in conditionString.Split(',', StringSplitOptions.RemoveEmptyEntries))
    {
        var cleanedCond = condItem.Trim();
        var op = supportOperators.First(o => cleanedCond.Contains(o));
        var parts = cleanedCond.Split(new[] { op }, StringSplitOptions.RemoveEmptyEntries);
        var fieldName = parts[0].Trim();
        var rawValue = parts[1].Trim().Trim('"', '\'');

        // 生成x["字段名"]的表达式
        Expression fieldAccess = Expression.Property(parameter, "Item", Expression.Constant(fieldName));
        Expression valueExp;
        Expression compareExp;

        // 根据值类型做对应的转换,避免字符串比较错误
        if (DateTime.TryParse(rawValue, out DateTime dateVal))
        {
            valueExp = Expression.Constant(dateVal);
            var convertMethod = typeof(JToken).GetMethod("ToObject", Type.EmptyTypes)!.MakeGenericMethod(typeof(DateTime));
            fieldAccess = Expression.Call(fieldAccess, convertMethod);
        }
        else if (double.TryParse(rawValue, out double numVal))
        {
            valueExp = Expression.Constant(numVal);
            var convertMethod = typeof(JToken).GetMethod("ToObject", Type.EmptyTypes)!.MakeGenericMethod(typeof(double));
            fieldAccess = Expression.Call(fieldAccess, convertMethod);
        }
        else
        {
            valueExp = Expression.Constant(rawValue);
            var convertMethod = typeof(JToken).GetMethod("ToString", Type.EmptyTypes)!;
            fieldAccess = Expression.Call(fieldAccess, convertMethod);
        }

        // 生成对应操作符的比较表达式
        compareExp = op switch
        {
            "=" => Expression.Equal(fieldAccess, valueExp),
            "!=" => Expression.NotEqual(fieldAccess, valueExp),
            ">" => Expression.GreaterThan(fieldAccess, valueExp),
            "<" => Expression.LessThan(fieldAccess, valueExp),
            ">=" => Expression.GreaterThanOrEqual(fieldAccess, valueExp),
            "<=" => Expression.LessThanOrEqual(fieldAccess, valueExp),
            _ => throw new NotSupportedException($"不支持的操作符:{op}")
        };

        // 拼接多个条件
        combinedCondition = Expression.AndAlso(combinedCondition, compareExp);
    }

    // 编译为可执行委托
    var filterFunc = Expression.Lambda<Func<JObject, bool>>(combinedCondition, parameter).Compile();
    return jArray.Where(filterFunc).ToList();
}

注意事项

  • 条件解析时必须优先匹配长度更长的操作符(例如>=要早于>匹配),避免拆分条件出错
  • 字符串值如果包含特殊字符需要提前转义,避免生成的表达式语法错误
  • 日期格式建议统一使用ISO标准格式(yyyy-MM-dd、yyyy-MM-dd HH:mm:ss),减少日期解析错误概率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:24:02