javascript - 安全高效的动态多标准数组过滤javascript

标签 javascript arrays filtering

我遇到一种情况,我需要使用动态过滤器(有时还需要复杂的过滤条件)来过滤数组。

我已经扩展了 Array 类来为此添加一个方法。只要我可以指定简单的过滤条件(例如 {gender: "m"}),并且我当然可以其中的一些条件,这就可以正常工作。

不过,我还想做的是指定更复杂的过滤条件,基本上是 Array.prototype.filter() 方法的动态回调函数。我可以让它与 eval() 一起使用,但性能很糟糕,并且“不要使用 eval()”在互联网上随处可见。

您对如何解决这个问题有什么建议吗?任何关于安全有效地预编译复杂过滤字符串的建议,例如 ("key1==key2 || (last=="Smith"&& sex=="m")

    <script>

    var People = [
        { first: 'Peter', last: 'Henderson', key1:0, gender: "m", key2:0  },
        { first: 'Paul', last: 'Paulson', key1: 10, gender: "m", key2:10   },
        { first: 'Mary', last: 'Miller', key1: 2, gender: "f", key2:0 },
        { first: 'Mary', last: 'Smith', key1: 3 , gender: "f" , key2:3  },
        { first: 'Peter', last: 'Smith' , key1: 4, gender: "m", key2:0 }
    ];
    console.log(People);
    var newPeople = MyArray.from(People).filterBy("@key1 == @key2");
    console.log(newPeople);
    newPeople = MyArray.from(People).filterBy({gender: "m", last:"Smith"});
    console.log(newPeople);
    </script>

classs MyArray extends Array {
  filterBy(argument) {
    return  this.filter(function(el){
      if (typeof argument == "object") {
        // object with key/parameter pairs for filtering:
        // {key1: 0, gender: "m"}
        for (let key in argument) {
          if (argument[key] !== el[key]) return false;
        };
        return true;
      } else if (typeof argument == "string") {
        // string with logical expression with key names @-escaped, e.g.
        // @gender == 'm' && @key1 == @key2
        let expression = argument.split("@").join("el.")
        return eval(expression);
      }
    });
  }
}

最佳答案

考虑这个问题的一种方法是您希望实现一种过滤操作的语言。与任何语言一样,这种语言可以具体化为抽象语法树,以便可以动态传递和获取。

根据您问题中的单个示例("key1==key2 || (last=="Smith"&& sex=="m"),假设您希望您的语言支持涉及文字值和输入字段的合取、析取和相等断言。

虽然不是绝对必要的,但将语言的 AST 建模为代数数据类型通常很方便。有很多库可以实现这一点,其中一个库的情况如下:

const { adt, match } = require("@masaeedu/adt")

// First, we build a language of references and predicates
const ref = adt({
  lit: ["some literal value"],
  key: ["the name of some field"]
})
const { lit, key } = ref

const predicate = adt({
  and: ["predicate", "predicate"],
  or: ["predicate", "predicate"],
  equals: ["ref", "ref"]
})

const { and, or, equals } = predicate

// Then we construct an expression in this language
// NB: you could also use a parsing library to parse this out of a string
const yourpredicate =
  or (equals (key ("key1")) (key ("key2")))
     (and (equals (key ("last")) (lit ("Smith")))
          (equals (key ("gender")) (lit ("m"))))

console.log(yourpredicate)
/* =>
{
  label: "or",
  values: [
    {
      label: "equals",
      values: [
        { label: "key", values: ["key1"] },
        { label: "key", values: ["key2"] }
      ]
    },
    {
      label: "and",
      values: [
        {
          label: "equals",
          values: [
            { label: "key", values: ["last"] },
            { label: "lit", values: ["Smith"] }
          ]
        },
        {
          label: "equals",
          values: [
            { label: "key", values: ["gender"] },
            { label: "lit", values: ["m"] }
          ]
        }
      ]
    }
  ]
}
*/

// Then we interpret our language into an actual predicate on some value
const resolve = ref.match({
  lit: v => _ => v,
  key: k => a => a[k]
})

const interpret = predicate.match({
  and: f => g => a => interpret(f)(a) && interpret(g)(a),
  or: f => g => a => interpret(f)(a) || interpret(g)(a),
  equals: r1 => r2 => a => resolve(r1)(a) === resolve(r2)(a)
})

const inputs = [
  { key1: "foo", key2: "bar", last: "Smith", gender: "m" },
  { key1: "foo", key2: "foo", last: "Hurpenglurper", gender: "m" },
  { key1: "foo", key2: "bar", last: "Hurpenglurper", gender: "m" }
]

const p = interpret(yourpredicate)

console.log(inputs.map(p))
// =>
// [true, true, false]

您可以运行该示例并在此处进行操作:https://runkit.com/masaeedu/reified-predicates

关于javascript - 安全高效的动态多标准数组过滤javascript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62344971/

相关文章:

python - 如何一次将函数应用于 Pandas 数据框中的多列

javascript - 使用 Javascript 仅隐藏链接/txt/div

javascript - 正则表达式在 IE 和 Chrome 中总是返回 false

javascript - 外部 Controller 指令中 Controller 的调用函数

c++ - 矩阵 vector 乘积函数的签名

javascript - 从 JavaScript 数组中删除对象

Promise 中的 Javascript 范围

arrays - 如何在 Swift 中按属性值对自定义对象数组进行排序

jquery - 使用复选框过滤数据表

node.js - 在发送之前过滤响应