动态过滤对象数组

时间:2018-02-12 23:26:37

标签: javascript arrays filter

var persons = [
  { Color: "Gold", Location: ["Down"] },
  { Color: "Silver", Location: ["Up", "Down"] },
  { Color: "Silver", Location: ["Up"] }
];

var criteria = [
   { Field: "Color", Values: ["Silver"] },
   { Field: "Location", Values: ["Up", "Down"] }
];

此处字段颜色的类型为String,而Location是一个数组。 我有人,然后有一个过滤标准。我需要一个输出,以便过滤器中选择的所有值都需要与数据匹配。因此,在提供的数据中,如果记录中有Silver,Up和Down,则只有那些记录可见。 (注意AND参数,任何地方都没有OR条件。)

所以输出将是:

{ Color: "Silver", Location: ["Up", "Down"] }

现在,如果过滤条件是:

var criteria = [
       { Field: "Color", Values: ["Silver"] },
       { Field: "Location", Values: ["Up"] }
    ];

输出将是:

{ Color: "Silver", Location: ["Up", "Down"] },
{ Color: "Silver", Location: ["Up"] }

所以你看到过滤器中的所有值都应与记录匹配。

3 个答案:

答案 0 :(得分:0)

我将问题分解为单独的功能。它比你的解决方案更冗长,但我确实认为它更具可读性。

另外:它确实有用。

var persons = [
  { Color: "Gold", Location: ["Down"] },
  { Color: "Silver", Location: ["Up", "Down"] },
  { Color: "Silver", Location: ["Up"] }
];

var criteria = [
   { Field: "Color", Values: ["Silver"] },
   { Field: "Location", Values: ["Up", "Down"] }
];

const arraysEqual = (arr1, arr2) => {
  // Very simple array comparison.
  if (arr1.length !== arr2.length) return false;
  arr1 = arr1.sort();
  arr2 = arr2.sort();
  for(let i=0; i < arr1.length; i++) {
    if (arr1[i] !== arr2[i]) return false;
  }
  return true;
};

let result = persons.filter(person => {
  // All criteria must match.
  for (let criterium of criteria) {
    if (criterium.Field === 'Color') {
      if (person.Color !== criterium.Values[0]) return false;
    }
    if (criterium.Field === 'Location') {
      if (!arraysEqual(person.Location, criterium.Values)) return false;
    }
  }
  // We didn't *not* match for anything, so we matched!
  return true;
});
console.log(result);

/*
{ Color: "Silver", Location: ["Down", "Up"] }
*/

有关正在运行的示例,请参阅https://repl.it/@niels_bom/GoldenIdealMicrobsd

答案 1 :(得分:0)

在第三次编辑之后,现在我清楚你想要什么 - 将数组作为另一个的子集。

var result = persons.filter(function (person) {
    return criteria.every(function (c) {
        var value = person[c.Field];
        if (typeof value === 'object') {
                return c.Values.length<=value.length && 
                c.Values.every(function(v,i){return value.includes(v) ;});
        }
        else
            return c.Values.indexOf(value) > -1;
    })
})

我还更新了你的jsfiddle:https://jsfiddle.net/gzL42dna/1/

同时结帐:How to compare arrays in JavaScript?

答案 2 :(得分:0)

我相信这有效。使用Set对部分匹配有很大帮助。如果您想要解释代码,请告诉我。

var persons = [
  { Color: "Gold", Location: ["Down"] },
  { Color: "Silver", Location: ["Up", "Down"] },
  { Color: "Silver", Location: ["Up"] }
];

var criteria = [
   { Field: "Color", Values: ["Silver"] },
   { Field: "Location", Values: ["Up", "Down"] }
];

console.log(match(persons, criteria));

function match(persons, criteria) {
  let personMatches = [...persons]
  for (let i=0; i < criteria.length; i++) {
    let {Field, Values} = criteria[i]
    personMatches = personMatches.filter(obj => {
      if (Array.isArray(obj[Field])) {
        return hasMatches(obj[Field], Values)
      } else {
        return Values.includes(obj[Field])
      }
    })
  }
  return personMatches
}

function hasMatches(arr1, criteria) {
  let criteriaSet = new Set(criteria)
  let personsSet = new Set(arr1)
  for (let el of criteriaSet) {
    if (!personsSet.has(el)) return false
  }
  return true
}