2012-03-16 59 views
16

是否可以結合Underscore的過濾器和地圖?我目前有兩個獨立的函數調用,但我想知道是否可以通過以某種方式將它們組合成單個調用來提高它們的效率。如何通過下劃線的地圖和過濾器實現最大效率?

基本上我有一個國家名稱數組 - 我想使用正則表達式過濾它們,然後將過濾的結果映射到DataItem對象的數組。這是我目前的代碼:

var filteredData = _.filter(allCountries, function(n, i){ 
    var re = RegExp("^" + searchString, "i"); 
    if (re.exec(n['country'].toLowerCase()) !== null) { 
    return true; 
    } 
}); 
var mappedData = _.map(filteredData, function(n, i){ 
    return new DataItem(i, n['name'], n['budget']); 
}); 

提高效率的任何其他技巧也將受到感謝。

回答

11

您可以使用each代替:

result = [] 
_.each(array, function(elem) { 
    if(elem.indexOf(search) == 0) 
     result.push(...whatever...) 

還要注意的是,你並不需要一個正則表達式,只是找出一個字符串用另一個開始。

+2

連鎖是每個人更喜歡的 – 2013-10-03 14:19:36

+0

@itcouldevenbeaboat:可以,我不會使用下劃線那麼多......在這種特殊情況下,每個'似乎都更具可讀性。 – georg 2013-10-03 14:36:21

+0

這不好,因爲現在你已經引入了不必要的,可變的結果變量。有人可能會說,在這種情況下你可能會使用'for'循環。 '鏈'是最好的選擇。 – spinningarrow 2015-04-14 16:57:15

33

下劃線通過_.chain提供了一個鏈接能力:

_.chain(allCountries) 
.filter(function(n, i) { ... }) 
.map(function(n, i) { ... }) 
.value(); // stop chaining and get the result 

相反的re.exec(...) !== null可以使用re.test(...),請注意,你需要轉義特殊字符的正則表達式爲searchString

在這個簡單的例子然而,最好使用.indexOf來檢查字符串是否以一個子開始:

// substring should be apparent at position 0, discard case for both strings 
return n.country.toLowerCase().indexOf(searchString.toLowerCase()) === 0; 

對於字符串常量,.foo可能比['foo']更清晰。

+0

這當然是一個答案! – nick4fake 2014-10-10 09:35:12

8

pimvdb的答案是我們在函數式編程中做的事情/ underscore.js 在同一時間執行這兩個步驟有點不成熟。 JS從單獨做這些事情中獲益不多。

_.chain(allCountries) 
.filter(function(n, i) { ... }) 
.map(function(n, i) { ... }) 
.value(); 

以上很容易理解,但是一旦我們開始合併責任事情就會變得毛茸茸的。

_.mapFilter(陣列,filterFn,mapFn)...

與鏈接我們犧牲效率性能。兩者都很重要,但總是比另一個更重要。我們不能回頭來提高生產力,但事實上我們可以提高績效。

+0

這值得讚賞! 「我們不能回頭去提高生產力,但我們可以在事後提高性能。」真棒概念! – 2017-02-17 01:17:41

11

使用_.reduce,因爲它節省了n迭代。將您的RegEx從循環中取出,以便在每次迭代時不重新創建對象。使用test而不是exec(更快,因爲它是一個簡單的布爾結果)。

var re = RegExp("^" + searchString, "i"); 
var data = _.reduce(allCountries, function(res, n, i) { 
    if (re.test(n['country'])) { 
    res.push(new DataItem(i, n['name'], n['budget'])); 
    } 
    return res; 
}, []);