我已经找到了许多具有多个条件的对象数组过滤器,但它们似乎是完全匹配的。我需要一种过滤部分匹配的方法。我似乎找到了一个。
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)
我正在使用此功能-效果很好!但是比赛必须是准确的。如何将其更改为部分匹配?还有大写还是小写?我尝试了很多方法,但似乎无法正常工作。任何帮助将不胜感激!
答案 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
处理值以进行比较。