筛选具有多个条件和部分匹配项的对象数组

时间:2018-12-05 19:22:36

标签: javascript arrays node.js filter

我已经找到了许多具有多个条件的对象数组过滤器,但它们似乎是完全匹配的。我需要一种过滤部分匹配的方法。我似乎找到了一个。

let products = [
  { name: "A", color: "Blue", size: 50 },
  { name: "B", color: "Blue", size: 60 },
  { name: "C", color: "Black", size: 70 },
  { name: "D", color: "Green", size: 50 },
];

let filters = {
  color: "Blue",
  size: "70"
};

function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters);
  return array.filter((item) => {
  return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
  });

var filtered = multiFilter(products, filters);

https://gist.github.com/jherax/f11d669ba286f21b7a2dcff69621eb72

我正在使用此功能-效果很好!但是比赛必须是准确的。如何将其更改为部分匹配?还有大写还是小写?我尝试了很多方法,但似乎无法正常工作。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

要转换现有代码,您需要像@Vasan所指出的那样切换过滤器。

这意味着将检查products中属性的值,以查看filters的匹配属性值是否是子字符串。但是products中的某些字段不是字符串。因此,我们将首先将它们全部转换为字符串,尽管我不确定搜索“ size:1”并被赋予“ size:100”项有多有用。

    let products = [
      { name: "A", color: "Blue", size: 50 },
      { name: "B", color: "Blue", size: 60 },
      { name: "C", color: "Black", size: 70 },
      { name: "D", color: "Green", size: 50 }
    ];
    
    let filters = {
      color: "Blu",
      size: "50"
    };

    function multiFilter(array, filters) {
      const filterKeys = Object.keys(filters);
      return array.filter((item) => {
        // flipped around, and item[key] forced to a string
        return filterKeys.every(key => !!~String(item[key]).indexOf(filters[key]));
      });
    }

    var filtered = multiFilter(products, filters);
    console.log(filtered);

答案 1 :(得分:1)

基本上,您正在寻找的是Regular Expression。您需要更改

filterKeys.every(key => !!filters[key].indexOf(item[key]))

成为

!filterKeys.some(key => RegExp(filters[key], 'i').test(item[key].toString()));

当然要小心使用item[key].toString(),因为根据情况的不同,它可能会给您带来问题,在这种情况下,由于数字(产品的尺寸钥匙),我会使用它。

let products = [{
    name: "A",
    color: "Blue",
    size: 50
  },
  {
    name: "B",
    color: "Blue",
    size: 60
  },
  {
    name: "C",
    color: "Black",
    size: 70
  },
  {
    name: "D",
    color: "Green",
    size: 50
  },
  {
    name: "D",
    color: "bluePartial", //you are looking for blue, but blue is a substring of bluepartial, this will be filtered as well
    size: 50
  },
  {
    name: "D",
    color: "violet",
    size: 700 // same as above, 70 is a substring of 700
  },
];

// the value of each key is an array with the values to filter
let filters = {
  color: "Blue",
  size: "70"
};

function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters);
  return array.filter((item) => {
    return !filterKeys.some(key => RegExp(filters[key], 'i').test(item[key].toString()));
  });
}

var filtered = multiFilter(products, filters);
console.log(filtered)

答案 2 :(得分:1)

您可以尝试以下操作:

let rows = [ { name: "A", color: "Blue", size: "50" }, { name: "B", color: "Blue", size: "60" }, { name: "C", color: "Black", size: "70" }, { name: "D", color: "Green", size: "50" }, ];

const filter = (a, f) => {
  let keys = Object.keys(f)
  if(keys.length == 1) {
    return a.filter(x => x[keys[0]].toLowerCase().includes(f[keys[0]].toLowerCase()))
  } else return a.filter(x => Object.values(f).every(fv => {
    return Object.values(x).some(v => v.toLowerCase().includes(fv.toLowerCase()))
  }))
}

console.log(filter(rows, {color: "Blu", size: "50"}))
console.log(filter(rows, {color: "G", size: "5"}))
console.log(filter(rows, {name: "b"}))
console.log(filter(rows, {size: "6"}))

这个想法是,如果您仅对字段值进行filter的1个过滤器(否则b将同时匹配name: "B"color: "Blue"而不是1个结果您将获得3),但是如果有多个对象可以过滤filter对象中的所有值。

代码使用String.includes处理部分匹配,并使用String.toLowerCase处理值以进行比较。