如何在javascript中动态构建数组过滤表达式



我需要一个函数来过滤我的数组,并根据用户输入返回结果。

var Myarray= [
{Date:"1-Jan-2020",Name:"A", Id: 1},
{Date:"1-Feb-2020",Name:"B", Id: 2},
{Date:"1-Mar-2020",Name:"C", Id: 3}
...
]

过滤器需要是动态的。用户必须至少输入日期或名称,或同时输入两者。ID为可选

有没有一种聪明的方法可以根据用户输入的内容在函数中构建过滤器表达式?

更多信息:我有一个用户界面。用户将有可供选择的返回日期搜索参数。日期、名称和ID。用户必须至少选择日期或名称。ID是可选的,但必须在接受发送的参数的函数中考虑。用户输入值后,它们被传递给JS函数,该函数应该过滤保存数据的数组。将过滤器应用于数组后,将用过滤后的数据填充一个新数组。例如,user发送不带名称或ID的Date,然后数组仅根据日期进行筛选。示例2.user发送不带日期或id的Name,然后只根据名称进行数组筛选。示例3.用户发送不带id的日期和名称,然后根据日期和名称进行数组筛选。Ex4.user发送不带名称的Date和id,然后根据日期和id进行数组筛选。Ex5。用户发送不带日期的名称和id,然后按名称和id进行数组筛选。ex6用户发送日期和名称以及id,然后根据日期和名称及id进行数组筛选器。Ex7用户发送id,函数将不允许在没有日期或名称的情况下单独发送id

您可以使用Array.prototype.some(OR(来链接谓词。如果在任何时候谓词匹配,则整个项将添加到结果列表中。

如果希望所有条件都匹配,则需要使用Array.prototype.every(AND(链接。

我可能会很快回到这一点,用一个更动态的例子 见下文

const main = () => {
let arr = [
{ Date: "1-Jan-2020" , Name: "A"  , Id: 1 }, // Yes
{ Date: "1-Feb-2020" , Name: "B"  , Id: 2 }, // Yes
{ Date: "1-Mar-2020" , Name: null , Id: 3 }, // Yes
{ Date: null         , Name: null , Id: 4 }  // No
]

console.log(filterWithPredicates(arr, predicates))
}
const predicates = {
date: (record) => record.Date != null,
name: (record) => record.Name != null
};
const filterWithPredicates = (list, predicates) => {
return list.filter(item => {
return Object.values(predicates).some(predicate => {
if (predicate(item)) { return true }
})
return false
})
}
main()
.as-console-wrapper { top: 0; max-height: 100% !important; }


这里有一个谓词链接的例子。

const Predicates = {
date: (record) => record.Date != null,
name: (record) => record.Name != null
}
const main = () => {
let arr = [
{ Date: "1-Jan-2020" , Name: "A"  , Id: 1 }, // Yes
{ Date: "1-Feb-2020" , Name: "B"  , Id: 2 }, // Yes
{ Date: "1-Mar-2020" , Name: null , Id: 3 }, // Yes
{ Date: null         , Name: null , Id: 4 }  // No
]

let filter = new Filter().chain().or(Predicates.date).or(Predicates.name)
console.log(filter.execute(arr))
}
class Filter {
constructor() {
this.filters = []
}
chain() {
this.filters = []
return this
}
or(predicate) {
this.filters.push({ fn : predicate, op : 'or' })
return this
}
and(predicate) {
this.filters.push({ fn : predicate, op : 'and' })
return this
}
execute(items) {
return items.reduce((results, item) => 
this.__shouldKeepItem(item) ? results.concat(item) : results, [])
}
/** @private */
__startCondition() {
return this.filters.length ? this.filters[0].op === 'and' ? 1 : 0 : 0
}
/** @private */
__shouldKeepItem(item) {
return this.filters.reduce((keep, filter) => {
switch (filter.op) {
case 'or'  : return keep || filter.fn(item)
case 'and' : return keep && filter.fn(item)
default    : return keep
}
}, this.__startCondition())
}
}
main()
.as-console-wrapper { top: 0; max-height: 100% !important; }

const Myarray= [
{Date:"1-Jan-2020",Name:"A", Id: 1},
{Date:"1-Feb-2020",Name:"B", Id: 2},
{Date:"1-Mar-2020",Name:"C", Id: 3}
];
const customFilter = (array, expr) => {
if (Object.keys(expr).length == 0) {
console.log("Error! missing at least one filter expression");
return null;
}
/* if expression doesn't exist it's a pass for all items */
return array.filter(item => !expr.Date || item.Date == expr.Date).filter(item => !expr.Name || item.Name == expr.Name).filter(item => !expr.Id || item.Id == expr.Id)
}
console.log(customFilter(Myarray, {Date: "1-Jan-2020", Name: "B"}))
console.log(customFilter(Myarray, {Date: "1-Jan-2020"}))
console.log(customFilter(Myarray, {Name: "B"}))
console.log(customFilter(Myarray, {Id: 3}))
console.log(customFilter(Myarray, {}))

尝试:

var filteredArray = Myarray.filter(function (item) {
return item.Date !== undefined && item.Name !== undefined;
});
var filteredArrayWithOptionalId = Myarray.filter(function (item) {
return item.Date !== undefined && item.Name !== undefined && item.Id !== undefined;
});

现在有两个数组,一个具有必需的参数对象,另一个可以处理可选的ID。然后,您可以循环使用filteredArrayWithOptionalId来处理与ID相关的代码。

请参阅此处类似问题的答案:如何根据属性筛选对象数组?

此外,我建议降低变量名的大小写,因为这是最佳实践,只要它们不是类。

最新更新