使用多个条件查询另一个数组来过滤一个数组

时间:2019-03-11 15:23:56

标签: javascript arrays reactjs

我有2个数组。一个包含这样的数据。

[{_id:123, Name: Mike, City: London},
{_id:456, Name: John, City: New York}]

另一个具有这样查询的数组。

[{fieldName: Name, operator: ===, value: Mike, logicalOperator: ||},
{fieldName: City, operator: !==, value: London, logicalOperator: ||},]

我们如何用第二个过滤第一个数组。

类似

data.filter(item => query.map(q => item.query.fieldName q.operator q.value)

3 个答案:

答案 0 :(得分:2)

您可以使用函数来表示比较操作:

[{
  fieldName: "Name",
  operator: (a, b) => a === b,
  value: "Mike", 
  logicalOperator: (a, b) => a || b,
}, {
  fieldName: "City",
  operator: (a, b) => a !== b, 
  value: "London", 
  logicalOperator: (a, b) => a || b
}]

然后就这么简单:

data.filter(item => query.reduce((acc, q) => q.locicalOperator(
   acc,
   q.operator(item[q.fieldName], q.value)
), true);

答案 1 :(得分:0)

您可以检查logicalOperator并使用someevery并使用操作数和运算符过滤数组。

function getFilter(filter) {
    var op = {
            '&&': (a, b) => a && b,
            '||': (a, b) => a || b,
            '!==': (a, b) => a !== b,
            '===': (a, b) => a === b,
            '<>': (a, b) => a !== b,
            '>=': (a, b) => a >= b,
//            'startsWith': (a, b) => a.startsWith(b), // see default example below
//            'endsWith': (a, b) => a.endsWith(b),
//            'includes': (a, b) => a.includes(b),
            default: k => (a, b) => a[k](b)            // works for any method
        },                                             // with this pattern
        fn = Array.prototype.reduce.bind(filter);

    return o => fn((a, { fieldName, operator, value, logicalOperator }, i) => {
        var b = (op[operator] || op.default(operator))(o[fieldName], value)
        if (!i) return b;
        return op[logicalOperator](a, b);
    }, undefined);
}

var data = [{ _id: 123, Name: 'Mike', City: 'London' }, { _id: 456, Name: 'John', City: 'New York' }],
    filter = [{ fieldName: 'Name', operator: '===', value: 'Mike', logicalOperator: '||' }, { fieldName: 'City', operator: '!==', value: 'London', logicalOperator: '||' }],
    result = data.filter(getFilter(filter))

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:0)

我有点偏离主题,但我想分享另一种使用prefix notation编写查询的方式。

operators = {
  "has" : function (v) { return this.hasOwnProperty(v); },
  "var" : function (v) { return this[v]; },
  "and" : (a, b) => a && b,
  "or" : (a, b) => a || b,
  "eq" : (a, b) => a === b
};

data = [
  { id : 789, name : "London", city : "London" },
  { id : 123, name : "John", city : "London" },
  { id : 234, name : "Mike", city : "London" },
  { id : 345, name : "John", city : "New York" },
  { id : 456, name : "Jack", city : "New York" },
  { id : 567, name : "James", city : "New York" },
  { id : 678, key : "value" }
];

queries = [
  "key === \"value\"", [
    "EQ", "VAR", "key", "value"
  ],
  "name === \"John\"", [
    "EQ", "VAR", "name", "John"
  ],
  "name === city", [
    "AND",
    "AND", "HAS", "name", "HAS", "city",
    "EQ", "VAR", "name", "VAR", "city"
  ],
  "name === \"John\" || city === \"London\"", [
    "OR",
    "EQ", "VAR", "name", "John",
    "EQ", "VAR", "city", "London"
  ],
  "id === 234 || name === \"John\" && city === \"New York\"", [
    "OR",
    "EQ", "VAR", "id", 234,
    "AND",
    "EQ", "VAR", "name", "John",
    "EQ", "VAR", "city", "New York"
  ],
  "city === \"New York\" && (name === \"John\" || name === \"James\")", [
    "AND",
    "EQ", "VAR", "city", "New York",
    "OR",
    "EQ", "VAR", "name", "John",
    "EQ", "VAR", "name", "James"
  ]
];

for (i = 0; i < queries.length; i += 2) {
  console.log(queries[i]);
  console.log(data.filter(
    (query => item => evaluate.call(item, query))(queries[i + 1])
  ).map(function (x) {
    return JSON.stringify(x);
  }).join("\n"));
}

function evaluate (expr) {
  var i, j, op, args, stack = [];
  for (i = expr.length - 1; i >= 0; i--) {
    op = typeof expr[i] !== "string" ? undefined : (
      operators[expr[i].toLowerCase()]
    );
    if (op === undefined) {
      stack.push(expr[i]);
    } else {
      args = new Array(op.length);
      for (j = 0; j < op.length; j++) {
        args[j] = stack.pop();
      }
      stack.push(op.apply(this, args));
    }
  }
  return stack.pop();
}