简体   繁体   English

动态过滤对象数组

[英]Dynamically filtering an array of objects

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"] }
];

Here field color is of type String, and Location is an array.这里的字段颜色是字符串类型,位置是一个数组。 I have persons, and then there is a filter criteria.我有人,然后有一个过滤条件。 I need an output so that all the values selected in the filter needs to match with the data.我需要一个输出,以便过滤器中选择的所有值都需要与数据匹配。 So in the data provided, only those records should be visible if Silver, Up and Down are available in a record.因此,在提供的数据中,如果 Silver、Up 和 Down 在记录中可用,则只有那些记录应该可见。 (Note the AND parameter, there is no OR condition anywhere). (注意 AND 参数,任何地方都没有 OR 条件)。

So the output will be:所以输出将是:

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

Now if the filter criteria is:现在,如果过滤条件是:

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

the output will be:输出将是:

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

So you see all the values in the filter should match with the records.所以你看到过滤器中的所有值都应该与记录匹配。

I broke down the problem into separate functions.我将问题分解为不同的功能。 It's way more verbose than your solution but I do think it's more readable.它比您的解决方案更冗长,但我确实认为它更具可读性。

Also: it does work.另外:它确实有效。

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"] }
*/

See https://repl.it/@niels_bom/GoldenIdealMicrobsd for a running example.有关运行示例,请参阅https://repl.it/@niels_bom/GoldenIdealMicrobsd

After third edit, now I am clear on what you want - to have an array as a subset of the other.第三次编辑后,现在我很清楚你想要什么 - 将一个数组作为另一个的子集。

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;
    })
})

I also updated your jsfiddle : https://jsfiddle.net/gzL42dna/1/我还更新了你的 jsfiddle: https ://jsfiddle.net/gzL42dna/1/

Also checkout: How to compare arrays in JavaScript?另请查看: 如何比较 JavaScript 中的数组?

I believe this works.我相信这有效。 Using a Set helps a lot with partial matches.使用Set对部分匹配有很大帮助。 Tell me if you would like an explanation of the code.告诉我你是否想要代码的解释。

 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 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM