[英]Filter/Reject Array of strings against multiple values using underscore
I'd like to _.filter
or _.reject
the cities
array using the filters
array 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'];
My progress so far: 到目前为止,我的进度:
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;
I'd like to DRY this up and use a more functional approach to achieve this if possible? 我想对此进行干燥,并在可能的情况下使用更具功能性的方法来实现这一目标?
A somewhat more functional version using Underscore might look like this: 使用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"]
I'm using vanilla JavaScript here (some() and filter()) but I hope you get the idea: 我在这里使用香草JavaScript(some()和filter()),但我希望你能明白:
const isValidCity = city => filters.some(filter => city.indexOf(filter) > -1)
const filteredCities = cities.filter(isValidCity)
Please note that this is a loop over a loop. 请注意,这是一个循环。 So the time complexity is O(n * m) here.
因此,这里的时间复杂度为O(n * m)。
In your example all city keys share the same pattern: country
+ /
+ city
. 在您的示例中,所有城市键共享相同的模式:
country
+ /
+ city
。 Your filters are all an exact match to the city
part of these names. 您的过滤器均与这些名称的
city
部分完全匹配。
If this is a certainty in your data (which it probably isn't...) , you could reduce the number of loops your code makes by creating a Map
or object
that stores each city per filter entry: 如果这是数据中的确定性(可能不是...) ,则可以通过创建一个
Map
或object
来存储每个过滤器条目的每个城市,从而减少代码的循环次数:
key
the part that you want the filter to match key
成为您希望过滤器匹配的部分 value
the original name value
设为原始名称 filters
and return the name at each key. filters
并在每个键处返回名称。 This approach always requires one loop through the data and one loop through the filters. 这种方法总是需要一个数据循环和一个过滤器循环。 For small array sizes, you won't notice a performance difference.
对于较小的阵列大小,您不会注意到性能差异。 When one of the arrays has length 1, you'll also not notice any differences.
当其中一个数组的长度为1时,您也不会注意到任何差异。
Again, note that this only works if there's a constant relation between your filters and 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']; 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);
Since you seem to be using AngularJS, you could utilize the built-in filter functionality. 由于您似乎正在使用AngularJS,因此可以利用内置的过滤器功能。 Assuming both the cities and filters array exist on your controller and you're displaying the cities array using
ng-repeat
, you could have something like this on your controller: 假设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;
}
}
And then in your template, you'd do something like this: 然后在模板中,您将执行以下操作:
<div ng-repeat="city in cities | filter : cityFilter"></div>
Of course you'd have to modify your syntax a bit depending on your code style (for example, whether you use $scope
or controllerAs
). 当然,您必须根据代码样式(例如,使用
$scope
还是controllerAs
)来稍微修改语法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.