[英]Javascript multiple condition array filter
我需要幫助來組合基於多個條件的數組搜索。 此外,所有條件都是有條件的,這意味着我可能需要也可能不需要根據這些條件進行過濾。 我擁有的:
要過濾的對象數組:
var data = [{
"_id" : ObjectId("583f6e6d14c8042dd7c979e6"),
"transid" : 1,
"acct" : "acct1",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 2,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 3,
"acct" : "acct2",
"transdate" : ISODate("2016-07-31T05:00:00.000Z"),
"category" : "category1",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 4,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category2",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
"transid" : 5,
"acct" : "acct2",
"transdate" : ISODate("2012-01-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
},
{
"_id" : ObjectId("583f6e6d14c8042dd7c152g2"),
"transid" : 6,
"acct" : "acct3",
"transdate" : ISODate("2016-10-31T05:00:00.000Z"),
"category" : "category3",
"amount" : 103
}]
我正在根據另一個混合元素數組過濾上述對象數組。 這些元素代表以下搜索字段:
“searchstring”:在數據數組的所有字段上搜索任何匹配的文本序列
object,鍵值代表帳戶類型,值的真或假指示是否應該用於過濾
過濾轉換日期的開始日期
過濾轉換的結束日期
過濾類別的類別名稱
具有搜索條件的數組如下所示(但如果某些字段不是必需的,它們將被設置為未定義或只是一個空字符串或數組):
var filtercondition = {
"p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
}
完成此任務的最佳方法是什么? 我設計的是單獨搜索過濾器數組中的每個元素,但這似乎不是最佳的並且非常乏味。 我願意重新設計我的設置......
// You wrote that it's an array, so changed the braces
var filtercondition = ["p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
];
var filtered = data.filter(o => {
if(filtercondition[0] && !o.category.includes(filtercondition[o])) { // checking just the category, but you can check if any of more fields contains the conditions
return false;
}
if(filtercondition[1]) {
for(var key in filtercondition[1]) {
if(filtercondition[1][key] === true && o.acct != key) {
return false;
}
}
}
if(filtercondition[2] && o.transdate < filtercondition[2]) {
return false;
}
if(filtercondition[3] && o.transdate > filtercondition[3]) {
return false;
}
if(filtercondition[4] && o.category !== filtercondition[4]) {
return false;
}
return true;
});
兩個注意事項: - 更改了filtercondition
的大括號,使其成為一個數組,但是我建議改用一個對象。 - 這個{acct1:true,acct2:false,acct3:true...}
樣本對我來說沒有意義,因為它表明acct
字段應該同時是acct1
和acct3
。
創建一個函數數組,每個函數代表一個條件。
這是一些演示該方法的示例代碼......
var conditions = [];
// Dynamically build the list of conditions
if(startDateFilter) {
conditions.push(function(item) {
return item.transdate >= startDateFilter.startDate;
});
};
if(categoryFilter) {
conditions.push(function(item) {
return item.cateogry === categoryFilter.category;
});
};
// etc etc
一旦有了條件數組,就可以使用Array.prototype.every對項目運行每個條件。
var itemsMatchingCondition = data.filter(function(d) {
return conditions.every(function(c) {
return c(d);
});
});
首先,您需要為數組使用方括號而不是花括號:
var filtercondition = [
"p",
{acct1:true,acct2:false,acct3:true...},
"2016-06-01",
"2016-11-30",
"category3"
];
再說一次,我不認為數組是最好的數據類型。 試試這樣的對象:
var filtercondition = {
query: "p",
accounts: {acct1:true,acct2:false,acct3:true...},
date1: "2016-06-01",
date2: "2016-11-30",
category: "category3"
};
然后,嘗試使用 Array.prototype.filter:
var filtered = data.filter(function(obj) {
for (var key in filtercondition) {
// if condition not met return false
}
return true;
});
我會使用一堆小的粒度函數並組合它們。
//only some utilities, from the top of my mind
var identity = v => v;
//string-related
var string = v => v == null? "": String(v);
var startsWith = needle => haystack => string(haystack).startsWith(needle);
var endsWith = needle => haystack => string(haystack).endsWith(needle);
var contains = needle => haystack => string(haystack).contains(needle);
//do sth with an object
var prop = key => obj => obj != null && prop in obj? obj[prop]: undefined;
var someProp = fn => obj => obj != null && Object.keys(obj).some(k => fn(k) );
var someValue = fn => obj => obj != null && Object.keys(obj).some(k => fn(obj[k]) );
//logic
var eq = b => a => a === b;
var not = fn => function(){ return !fn.apply(this, arguments) };
var and = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) && b.apply(this, arguments);
});
var or = (...funcs) => funcs.reduce((a, b) => function(){
return a.apply(this, arguments) || b.apply(this, arguments);
});
//composition
var compose = (...funcs) => funcs.reduce((a, b) => v => return a(b(v)));
var chain = (...funcs) => funcs.reduceRight((a, b) => v => return a(b(v)));
//and whatever else you want/need
//but stay granular, don't put too much logic into a single function
和一個示例組合:
var filterFn = and(
//some value contains "p"
someValue(contains("p")),
//and
chain(
//property "foo"
prop("foo"),
or(
//either contains "asdf"
contains("asdf"),
//or startsWith "123"
startsWith("123")
)
),
)
由於我不知道您如何構建過濾條件,因此我無法確切地告訴您如何將它們解析為這樣的組合,但您可以像這樣組合它們:
//start with something basic, so we don't ever have to check wether filterFn is null
var filterFn = identity;
//and extend/compose it depending on some conditions
if(/*hasQuery*/){
filterFn = and(
// previous filterFn(obj) && some value on obj contains `query`
filterFn,
someValue(contains(query)))
)
}
if(/*condition*/){
//extend filterFn
filterFn = or(
// (obj.foo === null) || previous filterFn(obj)
chain(prop("foo"), eq(null)),
filterFn
);
}
等等
先說幾點:
如果您打算在瀏覽器中使用它,您的data
對象將無效。 可能數據來自MongoDB
,對吧? 您的后端(數據源)應該有一種方法可以對其進行正確編碼並刪除ObjectID
和ISODate
引用。
您的filtercondition
條件不是有效的 JavaScript 對象/JSON。 檢查我的例子。
因此,您可以使用Array#filter方法過濾數據數組。
類似的東西:
let data = [{
"_id" : "583f6e6d14c8042dd7c979e6",
"transid" : 1,
"acct" : "acct1",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category1",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 2,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category2",
"amount" : 103
},
{
"_id" : "583f6e6d14c8042dd7c2132t6",
"transid" : 5,
"acct" : "acct2",
"transdate" : "2012-01-31T05:00:00.000Z",
"category" : "category3",
"amount" : 103
}];
let filterToApply = {
acct: {
acct1: true,
acct2: false,
acct3: true
},
initialDate: "2016-06-01",
finalDate: "2016-11-30",
category: "category3"
}
let filterData = (array, filter) => {
return array.filter( (item) => {
/* here, you iterate each item and compare with your filter,
if the item pass, you must return true. Otherwise, false */
/* e.g.: category check (if present only) */
if (filter.category && filter.category !== item.category)
return false;
}
/* add other criterias check... */
return true;
});
}
let dataFiltered = filterData(data, filterToApply);
console.log(dataFiltered);
如果你想用多個條件過濾一個數組,並且條件可以是可選的,那么使用下面的方法。
const data = [ { name: 'John', age: 25, city: 'New York' }, { name: 'John', age: 25, city: 'New' }, { name: 'Jane', age: 32, city: 'Los Angeles' }, { name: 'Bob', age: 45, city: 'New York' }, { name: 'Alice', age: 38, city: 'Los Angeles' } ]; const filteredData = (n, c, a) => data.filter(item => { if (n || c || a) { return (n? item.name === n: true) && (c? item.city === c: true) && (a? item.age === a: true); // keep adding conditons as much as u want } }); console.log(filteredData('John', null, 25)); console.log(filteredData(null, 'Los Angeles', 38)); console.log(filteredData(null, 'Los Angeles', null));
您可以鏈接盡可能多的條件
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.