我有一个包含食谱的JSON文件。 现在我的主页上有一个搜索栏,用户可以在其中选中和取消选中复选框,以选择要搜索的食谱属性(名称,成分,标签,类别)。他还可以检查多个条件。
现在,我想根据所选条件过滤对象。 我知道是否只有例如选中我可以使用的“ 名称”
recipes.filter(e -> e.name.indexOf(searchString) >= 0)
但是我该如何动态地说“如果还要对成分进行过滤,以找到名称为OR的结果”。
希望您能理解。谢谢。
答案 0 :(得分:1)
您可以将所有属性放入数组中,然后使用.some()
检查是否有任何属性匹配。
const recipes = [
{ name: "pizza", ingredients: "dough tomato mince", category: "meal" },
{ name: "pie", ingredients: "dough sugar", category: "dessert" },
{ name: "stew", ingredients: "potato mince onoin", category: "meal" },
{ name: "donut", ingredients: "sugar", category: "dessert" }
];
// Get these from the checkboxes:
const selected_attributes = [
"name",
"ingredients"
];
// Get this from the searchbar:
const seachbar_query = "do";
// Filter all recipes where the name or ingredients contains "do".
// We expect "pizza" and "pie', which contain dough in their ingredients.
// And we also expect "donuts", whose name starts with "do"
const filtered = recipes.filter( recipe => {
return selected_attributes.some( attribute => {
return recipe[ attribute ].includes( seachbar_query );
});
});
console.log( filtered );
答案 1 :(得分:0)
编写一个函数。
recipes.filter(e => {
if (whatever) return true;
else {
// additional checks.
}
});
就您而言,我猜是这样的:
recipes.filter(e => {
if (ingredientsAreChecked()) {
return e.name.matchesSearchString() || e.ingredients.some(i => i.matchesSearchString());
}
else {
return e.name.matchesSearchString();
}
});
或者如果ingredientsAreChecked()
不是计算上很轻松的事情,请执行以下操作:
if (ingredientsAreChecked()) return recipes.filter(e => ...);
else return recipes.filter(e => ...);
答案 2 :(得分:0)
filter
是一个高阶函数,它采用一个谓词函数,根据当前项应保留还是不返回true
或false
。在您的情况下,该功能是单一代码,但可以传递任何类型的功能。
因此,如果您有复杂的逻辑,建议您将其移到一个命名函数中,在该函数中可以检查多个条件,最后返回一个布尔值:
function isRecipeValid(recipe) {
if (recipe.something) return false;
// any arbitrary conditional checking here
return recipe.conditionOne && recipe.conditionTwo;
}
recipes.filter(isRecipeValid);
答案 3 :(得分:0)
因此,您有两件事:搜索词和字段进行搜索。
您可以构建一个过滤函数,该函数接受这两个记录和一个记录(单个配方)并返回true或false。
假设您的复选框为name
,description
,ingreedients
。
您要做的是向过滤器函数发送项目名称,还向您发送要搜索的字段名称。然后在其中插入值。
您可能会遇到这样的事情:
// Disclaimer: these recipes are made up
const recipes = [{
name: 'lemon cake',
description: 'a delicious cake',
ingreedients: ['lemon', 'flour', 'sugar'],
},
{
name: 'sour lemon cake',
description: 'a delicious cake',
ingreedients: ['lemon', 'flour', 'not sugar'],
},
{
name: 'choco brownie',
description: 'a sweet chocolate desert',
ingreedients: ['chocolate', 'milk', 'flour', 'salt', 'sugar'],
},
{
name: 'vanilla croissant',
description: 'a yummy pastry with vanilla flavour',
ingreedients: ['vanilla', 'milk', 'flour'],
}
];
// To search, we need the search term, and an array of fields by which to search
// We return ANY match, meaning if the search term is in any of the fields, it's a match
function searchAnyField(searchTerm, searchFields) {
return recipes.filter(item => {
for (let field of searchFields) {
if (item[field].indexOf(searchTerm) > -1) {
return true;
}
}
return false;
});
}
// the same, but we make sure the search term exists in ALL fields (seems dumb here, but could be a req)
function searchAllFields(searchTerm, searchFields) {
return recipes.filter(item => {
// A naive approach is to count in how many fields did we find the term and if it matches the search fields length
let foundInFields = 0;
for (let field of searchFields) {
if (item[field].indexOf(searchTerm) > -1) {
foundInFields++;
}
}
return foundInFields === searchFields.length;
});
}
// Let's see it in action
// we'lll just print out the names of found items
console.log('Brownie in name:', printNames(
searchAnyField('brownie', ['name'])));
console.log('Cake in name:', printNames(
searchAnyField('cake', ['name'])));
// Let's try multiple fields
console.log('Choc in name and desc:', printNames(
searchAnyField('choc', ['name', 'description'])));
console.log('flour anywhere:', printNames(
searchAnyField('flour', ['name', 'description', 'ingreedients'])));
console.log('sweet anywhere:', printNames(
searchAnyField('sweet', ['name', 'description', 'ingreedients'])));
// How about AND search:
console.log('cake in name AND desc:', printNames(
searchAllFields('cake', ['name', 'description'])));
console.log('cake everywhere:', printNames(
searchAllFields('cake', ['name', 'description', 'ingreedients'])));
function printNames(recipes) {
return recipes.map(r => r.name).join(', ');
}
编辑:您还说过,您有一些嵌套的道具等。以下是更多有关如何解决此问题的示例。
const FIELDS = {
name: {
type: 'string',
path: 'name',
},
description: {
type: 'string',
path: 'name',
},
ingreedients: {
type: 'array',
path: 'name',
},
price: {
type: 'nested',
path: 'details.price',
nestedType: 'number',
}
}
// Disclaimer: these recipes are made up
const recipes = [{
name: 'lemon cake',
description: 'a delicious cake',
ingreedients: ['lemon', 'flour', 'sugar'],
details: {
price: 45,
}
},
{
name: 'sour lemon cake',
description: 'a delicious cake',
ingreedients: ['lemon', 'flour', 'not sugar'],
details: {
price: 45,
}
},
{
name: 'choco brownie',
description: 'a sweet chocolate desert',
ingreedients: ['chocolate', 'milk', 'flour', 'salt', 'sugar'],
details: {
price: 42,
},
},
{
name: 'vanilla croissant',
description: 'a yummy pastry with vanilla flavour',
ingreedients: ['vanilla', 'milk', 'flour'],
details: {
price: 45,
},
}
];
// To search, we need the search term, and an array of fields by which to search
// We return ANY match, meaning if the search term is in any of the fields, it's a match
function searchAnyField(searchTerm, searchFields) {
return recipes.filter(item => {
for (let field of searchFields) {
switch (field.type) {
case 'string':
if (item[field.path].indexOf(searchTerm) > -1) {
return true;
}
case 'array':
if (item[field.path].includes(searchTerm) > -1) {
return true;
}
case 'nested':
const props = field.path.split('.').reverse();
let prop = props.pop();
let val = item[prop];
while (val && props.length > 0) {
prop = props.pop();
val = val[prop]
}
if (field.nestedType === 'string') {
if (val && val.indexOf(searchTerm) > -1) {
return true;
}
} else if (field.nestedType === 'number') {
return val == searchTerm;
}
}
}
});
return false;
}
// Let's see it in action
// we'lll just print out the names of found items
console.log('42 anywhere:', printNames(
searchAnyField(42, [ FIELDS.price])));
console.log('42 anywhere:', printNames(
searchAnyField(42, [ FIELDS.price, FIELDS.name])));
function printNames(recipes) {
return recipes.map(r => r.name).join(', ');
}