【问题标题】:Dynamically filtering an array of objects with n filter criteria使用 n 个过滤条件动态过滤对象数组
【发布时间】:2018-04-19 09:43:19
【问题描述】:

我有一个对象(数据)数组,我需要根据过滤条件(条件)过滤这个数组,其中每个条件可以有多个值。

var data = [
  { ID: 1, Name: "John", Color: "Blue", Location: "Up" },
  { ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
  { ID: 3, Name: "Ahmed", Color: "Orange", Location: "Left" },
  { ID: 4, Name: "Diego", Color: "Pink", Location: "Up" },
  { ID: 5, Name: "Maria", Color: "Black", Location: "Down" },
  { ID: 6, Name: "Gus", Color: "Green", Location: "Up" },
  { ID: 7, Name: "Brian", Color: "Pink", Location: "Left" },
  { ID: 8, Name: "Shelley", Color: "Green", Location: "Right" },
  { ID: 9, Name: "Leonardo", Color: "Blue", Location: "Right" },
  { ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" }
];

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

我需要一个对象数组(过滤) 1.每个过滤条件都被视为“AND” 2. 一个过滤器字段中的多个过滤器值被视为“或”。所以输出应该是这样的:

var filtered = [
      { ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
      { ID: 6, Name: "Gus", Color: "Green", Location: "Up" },  
      { ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" }  
    ];

【问题讨论】:

标签: javascript arrays filter


【解决方案1】:

您可以将Array.every 用于AND 条件,将array.indexOf 用于OR 条件。

注意,indexOf 区分大小写。如果你想让它不区分大小写,你可以将两个值都转换为小写并比较

var data = [
  { ID: 1, Name: "John", Color: "Blue", Location: "Up" },
  { ID: 2, Name: "Pauline", Color: "Green", Location: "Up" },
  { ID: 3, Name: "Ahmed", Color: "Orange", Location: "Left" },
  { ID: 4, Name: "Diego", Color: "Pink", Location: "Up" },
  { ID: 5, Name: "Maria", Color: "Black", Location: "Down" },
  { ID: 6, Name: "Gus", Color: "Green", Location: "Up" },
  { ID: 7, Name: "Brian", Color: "Pink", Location: "Left" },
  { ID: 8, Name: "Shelley", Color: "Green", Location: "Right" },
  { ID: 9, Name: "Leonardo", Color: "Blue", Location: "Right" },
  { ID: 10, Name: "Big Daddy", Color: "Green", Location: "Down" },
  { ID: 11, Name: "Dummy", Color: ["Green", "Orange"], Location: "Down" }
];

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

var result = data.filter(function(obj){
  return criteria.every(function(c){
    var value = obj[c.Field];
    if(typeof value === 'object') {
      return Object.keys(value).some(function(key){
        return c.Values.indexOf(value[key]) > -1
      })
    }
    else
      return c.Values.indexOf(value) > -1
  })
})
console.log(result)

【讨论】:

  • 我使用了完全相同的逻辑,但做了一些否定的事情。你提供了一个更优雅的答案
  • 是的,我看到了你的答案。只是一个指针,这些函数是函数式编程的一部分,旨在使代码易于阅读。 !some 需要时间来理解。其过滤满足所有条件的数据 vs 过滤不满足任何一个条件的数据。两者都可以,但您应该选择更易于阅读和关联的一种。
  • 我同意!这就是为什么你的答案比我的更优雅。
  • @Rajesh 。感谢您的回答。但是,如果其中一个假设数据的字段之一是数组 { ID: 3, Name: "Ahmed", Color: ["Orange", "Green"], Location: "Left" },那么将如何我处理过滤?
  • @sonal 在标准中的颜色是orange,那么这个对象应该被认为是有效的吗?
【解决方案2】:

Array.some 为任何匹配提供 true ,为每个不匹配提供 false 。我们期望一个假然后否定它,这样我们对原始数据的过滤标准是正确的。

filteredData = data.filter(d => 
  !(criteria.some(criterion => 
    criterion.Values.indexOf(d[criterion.Field]) === -1
   ))
)

【讨论】:

  • 另外,既然你已经在使用 ES6 特性,你也可以使用array.includes
猜你喜欢
  • 2022-11-30
  • 2021-07-05
  • 1970-01-01
  • 2022-01-10
  • 2020-06-24
  • 1970-01-01
  • 2019-09-15
  • 2022-09-24
  • 1970-01-01
相关资源
最近更新 更多