簡體   English   中英

使用下划線針對多個值過濾/拒絕字符串數組

[英]Filter/Reject Array of strings against multiple values using underscore

我想使用下划線使用filters數組來_.filter_.reject cities數組。

var cities = ['USA/Aberdeen', 'USA/Abilene', 'USA/Akron', 'USA/Albany', 'USA/Albuquerque', 'China/Guangzhou', 'China/Fuzhou', 'China/Beijing', 'China/Baotou', 'China/Hohhot' ... ]
var filters = ['Akron', 'Albuquerque', 'Fuzhou', 'Baotou'];

到目前為止,我的進度:

var filterList;

if (reject) {
    filterList = angular.copy(cities);
    _.each(filters, (filter) => {
        filterList = _.reject(filterList, (city) => city.indexOf(filter) !== -1);
    });
} else {
    filterList = [];
    _.each(filters, (filter) => {
        filterList.push(_.filter(cities, (city) => city.indexOf(filter) !== -1));
    });
}

filterList = _.flatten(filterList);

return filterList;

我想對此進行干燥,並在可能的情況下使用更具功能性的方法來實現這一目標?

使用Underscore的更具功能性的版本可能如下所示:

const cities = ['USA/Aberdeen', 'USA/Abilene', 'USA/Akron', 'USA/Albany', 
                'USA/Albuquerque', 'China/Guangzhou', 'China/Fuzhou',
                'China/Beijing', 'China/Baotou', 'China/Hohhot']
const filters = ['Akron', 'Albuquerque', 'Fuzhou', 'Baotou'];

var inList = names => value => _.any(names, name => value.indexOf(name) > -1);

_.filter(cities, inList(filters));
//=> ["USA/Akron", "USA/Albuquerque", "China/Fuzhou", "China/Baotou"]

_.reject(cities, inList(filters));
//=> ["USA/Aberdeen", "USA/Abilene", "USA/Albany", 
//    "China/Guangzhou", "China/Beijing", "China/Hohhot"]

我在這里使用香草JavaScript(some()和filter()),但我希望你能明白:

const isValidCity = city => filters.some(filter => city.indexOf(filter) > -1)

const filteredCities = cities.filter(isValidCity)

請注意,這是一個循環。 因此,這里的時間復雜度為O(n * m)。

在您的示例中,所有城市鍵共享相同的模式: country + / + city 您的過濾器均與這些名稱的city部分完全匹配。

如果這是數據中的確定性(可能不是...) ,則可以通過創建一個Mapobject來存儲每個過濾器條目的每個城市,從而減少代碼的循環次數:

  • 創建一個帶有每個城市名稱的條目的對象
  • 使key成為您希望過濾器匹配的部分
  • value設為原始名稱
  • 循環瀏覽filters並在每個鍵處返回名稱。

這種方法總是需要一個數據循環和一個過濾器循環。 對於較小的陣列大小,您不會注意到性能差異。 當其中一個數組的長度為1時,您也不會注意到任何差異。

同樣,請注意,這僅在過濾條件和城市之間存在恆定關系時才有效。

 var cities = ['USA/Aberdeen', 'USA/Abilene', 'USA/Akron', 'USA/Albany', 'USA/Albuquerque', 'China/Guangzhou', 'China/Fuzhou', 'China/Beijing', 'China/Baotou', 'China/Hohhot' ] var filters = ['Akron', 'Albuquerque', 'Fuzhou', 'Baotou']; const makeMap = (arr, getKey) => arr.reduce( (map, x) => Object.assign(map, { [getKey(x)]: x }), {} ); const getProp = obj => k => obj[k]; const getKeys = (obj, keys) => keys.map(getProp(obj)); // Takes the part after the "/" const cityKey = c => c.match(/\\/(.*)/)[1]; const cityMap = makeMap(cities, cityKey); const results = getKeys(cityMap, filters); console.log(results); 

由於您似乎正在使用AngularJS,因此可以利用內置的過濾器功能。 假設city和filter數組同時存在於您的控制器上,並且您正在使用ng-repeat顯示city數組,那么您的控制器上可能會有類似的內容:

function cityFilter(city) {
    var cityName = city.split('/')[1];
    if (reject) {
        return filters.indexOf(cityName) === -1;
    } else {
        return filters.indexOf(cityName) > -1;
    }
}

然后在模板中,您將執行以下操作:

<div ng-repeat="city in cities | filter : cityFilter"></div>

當然,您必須根據代碼樣式(例如,使用$scope還是controllerAs )來稍微修改語法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM