2017-01-13 101 views
2

我需要幫助把基於多個條件的數組搜索放在一起。此外,所有條件都是有條件的,這意味着我可能需要也可能不需要對這些條件進行過濾。我有什麼:Javascript多狀態數組過濾器

對象的數組進行過濾:

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的」:在數據陣列中的所有字段搜索任何 匹配的文本序列

  • 與關鍵值reprsenting帳戶類型和真正的或對象用於指示是否應當用於過濾

  • STARTDATE對

  • endd過濾transdate值假 吃過濾transdate

  • 類別名稱上

具有搜索條件的數組類似過濾器類別(但如果某些字段是沒有必要的,他們將被設置爲未定義或只是一個空的字符串或數組):

var filtercondition = { 
    "p", 
    {acct1:true,acct2:false,acct3:true...} 
    "2016-06-01", 
    "2016-11-30", 
    "category3" 
} 

完成此操作的最佳方法是什麼?我設計的是對濾鏡數組中的每個元素進行單獨搜索,但這看起來不是最佳的,而且非常單調乏味。我打開我的設置進行重新設計...

+0

什麼是數據的預期大小?它預計在哪裏運行?最近的電腦?移動?舊電腦?服務器強大? 「最好的方式」真的取決於多種因素。 – niry

回答

1
// 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字段應同時爲acct1acct3

+0

謝謝。這個解決方案爲我工作。在所有其他條件失敗的情況下,我會對您的建議代碼進行輕微修改以「返回true」,否則返回任何內容。 –

1

首先,你需要使用括號內爲你的陣列不是花括號:話又說回來

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; 
}); 
0
創建

函數數組,表示的狀態的各功能。

下面是這表明該方法的一些示例代碼...

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); 
    }); 
}); 
0

首先,一些要點:

  • data對象是無效的,如果你要在瀏覽器中使用它。數據可能來自MongoDB,對吧?您的後端(數據源)應該有一個方法來正確編碼它並刪除ObjectIDISODate引用。您的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); 
+0

'所以,你可以使用Array#過濾器方法對數據數組進行排序。#Array#filter不是Array#sort;) – Thomas

+0

@Thomas修復!謝謝 – mrlew

0

我會去一堆小粒度函數並撰寫它們。

//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 => a => b => 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") 
     ) 
    ), 
) 

,因爲我不知道你如何建立你的filterconditions,我不能確切地告訴你如何把它解析爲這樣的組合,但你可以撰寫他們像這樣:

//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 
    ); 
}