基于多值对象过滤javascript对象数组

Posted

技术标签:

【中文标题】基于多值对象过滤javascript对象数组【英文标题】:Filter javascript objects array based on a multivalue object 【发布时间】:2020-07-04 15:49:53 【问题描述】:

需要根据具有多个值组成数组的过滤器对象来过滤数组

    var vendors = [
      
        vendor_name: "John",
        region: ["APAC", "UKDE"],
        scanned_status: "Yes",
        channel: ["FILE", "API"],
        pii_attributes: ["A", "B"]
      ,
      
        vendor_name: "Onir",
        region: ["APAC", "LATAM"],
        scanned_status: "No",
        channel: ["FILE"],
        pii_attributes: ["A", "C"]
      ,
      
        vendor_name: "Suresh",
        region: ["UKDE", "NA"],
        scanned_status: "Yes",
        channel: ["API"],
        pii_attributes: ["C", "B"]
      
    ];

    var filterCriteria = 
      region: ["APAC", "LATAM"], // 'APAC', 'LATAM', 'NA', 'UKDE'
      channel: ["API"], // 'API', 'FILE'
      attributes: ["A", "B"],
      scan_status: "Yes" // 'Yes', 'No', 'All'
    ;
    let filtered_vendors = [];
    var result = vendors.filter((el, index, arr) => 
      if (
        filterCriteria["region"].includes(el["region"]) &&
        filterCriteria["channel"].includes(el["channel"]) &&
        filterCriteria["attributes"].includes(el["pii_attributes"])
      ) 
        filtered_vendors.push(el);
        return true;
      
      return false;
    );

    console.log(result);
    console.log(filtered_vendors);

但我无法在过滤器级别应用多次迭代以包含元素。想知道过滤数组的有效方法。

【问题讨论】:

是否(例如)filterCriteria.region 必须包含来自vendors[].region所有 个值或任何 个值? 其中任何一个都可以。 看看'some()' developer.mozilla.org/fr/docs/Web/javascript/Reference/… 【参考方案1】:

我不得不稍微解释一下你的问题。因此,在下面的代码中,我们检查每个过滤器是否过滤器属性值的 所有 元素也在给定的供应商对象属性中(基本上是子集操作)。如果您为每个过滤器指定 any 元素,则需要使用交集操作。

为了实现这一点,我们可以使用reduce 进行迭代,并使用&&(函数isSupersetOf)总结各个检查。要将其应用于每个过滤器属性,我们可以对条目集应用相同的技术(函数 isMatch)。

请注意,我还必须调整属性名称才能使其正常工作。

代码:

var vendors = [
      
        vendor_name: "John",
        region: ["APAC", "UKDE"],
        scanned_status: "Yes",
        channel: ["FILE", "API"],
        pii_attributes: ["A", "B"]
      ,
      
        vendor_name: "Onir",
        region: ["APAC", "LATAM"],
        scanned_status: "No",
        channel: ["FILE"],
        pii_attributes: ["A", "C"]
      ,
      
        vendor_name: "Suresh",
        region: ["UKDE", "NA"],
        scanned_status: "Yes",
        channel: ["API"],
        pii_attributes: ["C", "B"]
      ,
      // Add a match for illustration
      
        vendor_name: "Denep",
        region: ["APAC", "LATAM", "NA"],
        scanned_status: ["Yes"],
        channel: ["API"],
        pii_attributes: ["A", "B", "C"]
      
    ];

    const filterCriteria = 
      region: ["APAC", "LATAM"], // 'APAC', 'LATAM', 'NA', 'UKDE'
      channel: ["API"], // 'API', 'FILE'
      pii_attributes: ["A", "B"],
      scanned_status: ["Yes"] // 'Yes', 'No', 'All'
    ;
    const isSupersetOf = (subset, superset) => 
      subset.reduce((result, next) => result && superset.includes(next), true);
    const isMatch = (filter, element) => 
      Object.entries(filter)
        .reduce((result, [property, values]) => result && isSupersetOf(values, element[property] || []), true)
    
    const filteredVendors = vendors.filter((el, index, arr) => 
      isMatch(filterCriteria, el))

    console.log(filteredVendors);

【讨论】:

【参考方案2】:

您也可以通过对filterCriteria 使用相同的键来采取动态方法。

此方法检查过滤器值是否为数组并迭代值并检查包含。

如果没有数组,则直接比较值。

var vendors = [ vendor_name: "John", region: ["APAC", "UKDE"], scanned_status: "Yes", channel: ["FILE", "API"], pii_attributes: ["A", "B"] ,  vendor_name: "Onir", region: ["APAC", "LATAM"], scanned_status: "No", channel: ["FILE"], pii_attributes: ["A", "C"] ,  vendor_name: "Suresh", region: ["UKDE", "NA"],
scanned_status: "Yes", channel: ["API"], pii_attributes: ["C", "B"] ],
    filterCriteria =  region: ["APAC", "LATAM"], channel: ["API"], pii_attributes: ["A", "B"], scanned_status: "Yes" ,
    filters = Object.entries(filterCriteria),
    result = vendors.filter(o => filters.every(([k, value]) => Array.isArray(value)
        ? value.some(v => o[k].includes(v)) // change to every if all have to match
        : o[k] === value
    ));

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

【讨论】:

【参考方案3】:
var data = [
    "id": 1,
    "term_id": 5,
    "type": "car"
  ,
  
    "id": 2,
    "term_id": 3,
    "type": "bike"
  ,
  
    "id": 3,
    "term_id": 6,
    "type": "car"
  
];

var result = data.filter(function(v, i) 
  return ((v["term_id"] == 5 || v["term_id"] == 6) && v.type == "car");
)

console.log(result)

【讨论】:

这如何回答这个问题?

以上是关于基于多值对象过滤javascript对象数组的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 通过数组过滤并仅基于一个值的匹配返回

如何在javascript中将对象数组过滤为另一个对象数组? [关闭]

Angular2使用管道基于对象数组过滤对象数组

根据 GPS 位置之间的距离过滤对象数组(javascript)

数组 - Javascript - 使用输入搜索过滤对象数组

javascript过滤对象数组