使用下划线过滤/拒绝多个值的字符串数组

时间:2017-04-16 14:54:16

标签: javascript functional-programming underscore.js

我想使用下划线使用_.filter数组_.rejectcities filters数组。

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;

我想干这个并尽可能使用更实用的方法来实现这个目标吗?

4 个答案:

答案 0 :(得分:3)

使用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"]

答案 1 :(得分:1)

我在这里使用了vanilla JavaScript(some()和filter()),但我希望你明白这个想法:

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

const filteredCities = cities.filter(isValidCity)

请注意,这是一个循环循环。所以这里的时间复杂度为O(n * m)。

答案 2 :(得分:1)

在您的示例中,所有城市密钥共享相同的模式:country + / + city。您的过滤条件与这些名称的city部分完全匹配。

如果您的数据确实存在(可能不是......),则可以通过创建Map来减少代码所产生的循环次数或者object每个过滤条目存储每个城市:

  • 创建一个对象,其中包含每个城市名称的条目
  • 使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);




答案 3 :(得分:0)

由于您似乎在使用AngularJS,因此可以使用内置过滤器功能。假设您的控制器上存在城市和过滤器阵列,并且您使用ng-repeat显示城市数组,则您的控制器上可能会显示以下内容:

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)。