【问题标题】:JS Array.filter with Dynamic Filter Criterion具有动态过滤条件的 JS Array.filter
【发布时间】:2023-03-21 04:29:02
【问题描述】:

如何动态声明一组过滤条件而不必指定过滤器的数量?

例如,如果我有一组数据,像这样:

var data = [ 
  { item: { type: 'wood', size: 10 } }, 
  { item: { type: 'wood', size: 8 } },
  { item: { type: 'metal', size: 8 } } 
]

我知道我可以使用 JS .filter() 来获取所有具有 type woodsize 8 的项目:

function filterItems() {
  return data.filter(function(val) {
    return val['item'].type == 'wood' && 
           val['item'].size == 8;
  }
}

但是,如果我想用未知数量的过滤器过滤项目,并让 .filter() 返回所有符合这些条件的 data 项目怎么办?

Here is a codepen反映了上面的代码。

【问题讨论】:

  • 如何将这些动态过滤条件传递给您的代码?
  • 我有一个服务 Javascript 文件,它接受动态输入,然后根据输入标准返回过滤后的数据。这是你想知道的吗?
  • 我会编写一个简单的比较器函数,然后将我的标准链接到一系列过滤器中,例如:r.filter(comp, ["type","wood"]).filter(comp, ["size",8);

标签: javascript


【解决方案1】:

您可以将一组条件传递给filterItems() 函数。试试这个:

function filterItems(filters) {
  return data.filter(function(val) {
    for(var i = 0; i < filters.length; i++)
      if(val['item'][filters[i][0]] != filters[i][1])
        return false;
    return true;
  }
}
filterItems([['type', 'wood'], ['size', 8], ['someother', 'value']]);

同样的想法可以应用于各种格式,例如使用对象而不是数组来提高可读性。

【讨论】:

  • 我想我明白你想向我展示的内容,你能清理一下你的代码吗?
  • 您在寻找什么清理方法?
  • Soo.. 没事吧?或不?我不明白(如果不是,请具体说明,你不“喜欢”什么?)
  • 这很好而且很有帮助。只是出于好奇,是否可以将for 循环放在data.filter 之外?
  • 没有。您需要针对所有条件测试任何val。您需要在过滤器功能中使用它。
【解决方案2】:

我刚刚对 Amit 的答案进行了一些重构,以支持任何数据结构和嵌套属性

// the function
filterItems = (data, filters) => data.filter(item => !filters.find(x => x.key.split('.').reduce((keys, key) => keys[key], item) !== x.value))

// how to use it
filterItems(data, [{ key: 'type', value: 'wood' }, { key: 'some.nested.prop', value: 'value' }])

【讨论】:

    【解决方案3】:
    function isSingle(filter) {
        return (filter && 'o' in filter && 'm' in filter && 'v' in filter);
    }
    
    function isComposite(filter) {
        return (filter && 'lo' in filter);
    }
    
    function createBody(filter) {
    
        if (isComposite(filter)) {
            var bdy = "";
            if (filter.v.length > 1) {
                var o = filter.lo;
                return "(" + createBody(filter.v.shift()) + " " + o + " " + createBody({ lo: filter.lo, v: filter.v }) + ")";
            } else if (filter.v.length == 1) {
                return createBody(filter.v.shift());
            }
            return bdy;
        } else if (isSingle(filter)) {
            var o = filter.o;
            if (typeof filter.v == "string") filter.v = "'" + filter.v + "'"
            return "item." + filter.m + " " + o + "  " + filter.v;
        }
    }
    var createFunc = function (filter) {
    
        var body = createBody(filter);
        var f = new Function("item", " return " + body + ";");
        return f;
    }
    
    function applyFilter(input, filter) {
        if (filter == undefined) {
            return input;
        }
    
        var fun = createFunc(filter);
        var output = input.filter(fun);
        return output;
    };
    //m:member,o:operator,v:value.
    
    var filterQuery1 = { m: "item.type", o: "==", v: "metal" };//simpe query
    var filterQuery2 = { m: "item.size", o: ">", v: 8 };
    var filterQuery3 = {
        lo: "&&", v: [
            { m: "item.type", o: "==", v: "metal" },
            { m: "item.size", o: "<", v: 9 }]
    }; //composite query
    var data = [
      { item: { type: 'wood', size: 10 } },
      { item: { type: 'wood', size: 8 } },
      { item: { type: 'metal', size: 8 } }
    ]
    var result = applyFilter(data, filterQuery1);// or filterQuery2,filterQuery3
    
    console.log(result);
    

    https://jsfiddle.net/kd0kL098/

    【讨论】:

    • 请用文字概括你的答案
    【解决方案4】:

    Amit 的回答很棒,但我想补充一下。就我而言,我需要返回所有参数,否则返回 none/false。这是来自 Amit 的编辑后的代码

    function filterItems(filters) {
      return data.filter(function(val) {
        let result = true;
        for(var i = 0; i < filters.length; i++)
          if(val['item'][filters[i][0]] != filters[i][1])
            result = false;
        return result;
      }
    }
    filterItems([['type', 'wood'], ['size', 8], ['someother', 'value']]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-24
      • 2020-04-24
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      • 2022-01-03
      • 2020-11-10
      • 1970-01-01
      相关资源
      最近更新 更多