筛选数组并比较但跳过空值



我目前正在尝试根据所选选项过滤可用产品。

const products = [{
id: 1,
name: 'Safari',
horsepowers: 30,
doors: 4,
gear_type: 'automatic',
wheels: 6
},
{
id: 2,
name: 'Jungle',
horsepowers: 50,
doors: 3,
gear_type: 'automatic',
wheels: 5
},
{
id: 3,
name: 'Moon',
horsepowers: 30,
doors: 4,
gear_type: 'manual',
wheels: 4
}
]
const selectedOptions = 
{
horsepowers: 50,
doors: 3,
gear_type: null,
wheels: null
}

通常我会做这样的事情

const availableProducts = products.filter((product) => 
product.horsepowers === selectedOptions.horsepowers &&
product.doors === selectedOptions.doors .... etc

但是,如果用户尚未选择所有可能的选项,如何跳过空值、空数组和未定义的值?

下一个提供的方法利用了几乎所有可用的原型数组方法的第二个thisArg参数。

因此,可以编写一个通用过滤器函数,该函数将任何项目的属性值与selectedOptions对象配置的相关值进行比较,该对象将与过滤器函数一起传递filter作为第二个参数和过滤器函数的this上下文......

const selectedOptions = {
horsepowers: 50,
doors: 3,
gear_type: null,
wheels: null,
};
const products = [{
id: 1,
name: 'Safari',
horsepowers: 30,
doors: 4,
gear_type: 'automatic',
wheels: 6,
}, {
id: 2,
name: 'Jungle',
horsepowers: 50,
doors: 3,
gear_type: 'automatic',
wheels: 5,
}, {
id: 3,
name: 'Moon',
horsepowers: 30,
doors: 4,
gear_type: 'manual',
wheels: 4,
}];
function doItemPropertiesEqualEveryBoundSelectedOption(item) {
return Object
// create key value pairs from the `this` bound selected options.
.entries(this)
// skip/ignore selected option entries where `value` equals `null`.
.filter(([key, value]) => value !== null)
// execute item specific selected option validation via `every`.
.every(([key, value]) => item[key] === value);    
}
console.log(
products
.filter(
doItemPropertiesEqualEveryBoundSelectedOption,
selectedOptions,
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

为了回答OP的另一个问题...

"但是,如果用户尚未选择所有可能的选项,如何跳过空值、空数组和未定义的值?">

。并且还为它提供了一个通用的解决方案,可以将上述方法更改为一个thisArg对象,该对象不仅具有选定的选项,而且还具有不被验证(无效)的条件selectedOption属性......

const products = [{
id: 1,
name: 'Safari',
horsepowers: 30,
doors: 4,
gear_type: 'automatic',
wheels: 6,
}, {
id: 2,
name: 'Jungle',
horsepowers: 50,
doors: 3,
gear_type: 'automatic',
wheels: 5,
}, {
id: 3,
name: 'Moon',
horsepowers: 30,
doors: 4,
gear_type: 'manual',
wheels: 4,
}];
const selectedOptions = {
horsepowers: 50,
doors: 3,
gear_type: null,
wheels: null,
};
const isInvalidValue = (value) => {
return Array.isArray(value)
// empty array validation.
? (value.length === 0)
// undefined and null value validation.
: (value == null)
}
function doItemPropertiesEqualEveryBoundValidOption(item) {
const { options, isInvalidValue } = this;
return Object
.entries(options)
.filter(([key, value]) => !isInvalidValue(value))
.every(([key, value]) => item[key] === value);    
}
console.log(
products
.filter(
doItemPropertiesEqualEveryBoundValidOption,
{ options: selectedOptions, isInvalidValue },
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

selectedOptions.horsepowers == null ? true : product.horsepowers === selectedOptions.horsepowers &&
product.doors == null ? true : product.doors === selectedOptions.doors

如果要使其保持一致,可以在比较之前使用三元运算符检查它是否为 null。

您可以先预处理selectedOptions,然后再比较:

const applicableOptions = Object.entries(selectedOptions).filter(
([_, value]) => value !== null && value !== undefined
);
const availableProducts = products.filter((product) =>
applicableOptions.every(([optKey, optValue]) => product[optKey] === optValue)
);

要使用数组进行比较,您需要更新您的示例,因为没有数组属性

与其手动输入每个选项,不如迭代selectedOptions.然后,就像在比较之前检查每个选项的值是否为空一样简单。

let filtered = products.filter(e => {
for(let [key, value] of Object.entries(selectedOptions))
{
if(value != null && e[key] != value)
return false;
}
return true;
});

const products = [{
id: 1,
name: 'Safari',
horsepowers: 30,
doors: 4,
gear_type: 'automatic',
wheels: 6
},
{
id: 2,
name: 'Jungle',
horsepowers: 50,
doors: 3,
gear_type: 'automatic',
wheels: 5
},
{
id: 3,
name: 'Moon',
horsepowers: 30,
doors: 4,
gear_type: 'manual',
wheels: 4
}
]
const selectedOptions = 
{
horsepowers: 50,
doors: 3,
gear_type: null,
wheels: null
}
let filtered = products.filter(e => {
for(let [key, value] of Object.entries(selectedOptions))
{
if(value != null && e[key] != value)
return false;
}
return true;
});
console.log(filtered);

但是,如果您真的想写出来,我只需检查该选项是否设置了简单的布尔检查。!(null)返回 true,因此这将起作用。

return (!selectedOptions.horsepowers || selectedOptions.horsepowers == product.horsepowers) && ...

您可以从selectedOptions生成一个过滤器数组并过滤条目,并在以后使用它来过滤数据。

const
products = [{ id: 1, name: 'Safari', horsepowers: 30, doors: 4, gear_type: 'automatic', wheels: 6 }, { id: 2, name: 'Jungle', horsepowers: 50, doors: 3, gear_type: 'automatic', wheels: 5 }, { id: 3, name: 'Moon', horsepowers: 30, doors: 4, gear_type: 'manual', wheels: 4 }],
selectedOptions = { horsepowers: 50, doors: 3, gear_type: null, wheels: null },
filter = Object
.entries(selectedOptions)
.filter(([, v]) => v !== null),
result = products.filter(o => filter.every(([k, v]) => o[k] === v));
console.log(result);

  • 使用Object#entriesArray#filter,从selectedOptions中获取具有选定值的对,以用于过滤产品列表
  • 使用Array#filterArray#every,过滤列表以确保生成的产品与上述对匹配

const 
products = [ { id: 1, name: 'Safari', horsepowers: 30, doors: 4, gear_type: 'automatic', wheels: 6 }, { id: 2, name: 'Jungle', horsepowers: 50, doors: 3, gear_type: 'automatic', wheels: 5 }, { id: 3, name: 'Moon', horsepowers: 30, doors: 4, gear_type: 'manual', wheels: 4 } ],
selectedOptions = { horsepowers: 50, doors: 3, gear_type: null, wheels: null };
const filterOptions = 
Object.entries(selectedOptions).filter(([_, value]) => value !== null);
const selectedProducts = 
products.filter(product =>
filterOptions.every(([key, value]) => product[key] === value)
);
console.log(selectedProducts);

最新更新