Javascript 使用下划线根据多个值筛选/拒绝字符串数组
我想使用Javascript 使用下划线根据多个值筛选/拒绝字符串数组,javascript,functional-programming,underscore.js,Javascript,Functional Programming,Underscore.js,我想使用过滤器或拒绝城市数组,使用过滤器数组使用下划线 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', 'Fu
过滤器或拒绝城市数组,使用过滤器数组使用下划线
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;
如果可能的话,我想干掉这一点,并使用更具功能性的方法来实现这一点?我在这里使用的是香草JavaScript(some()和filter()),但我希望您能理解:
const isValidCity = city => filters.some(filter => city.indexOf(filter) > -1)
const filteredCities = cities.filter(isValidCity)
请注意,这是一个循环对一个循环。所以这里的时间复杂度是O(n*m)。因为您似乎在使用AngularJS,所以可以利用内置的过滤器功能。假设控制器上同时存在cities和filters数组,并且您正在使用ng repeat
显示cities数组,则控制器上可能会有如下内容:
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>
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"]
当然,您必须根据您的代码样式稍微修改语法(例如,您是使用$scope
还是controllerAs
)。使用下划线的功能性更强的版本可能如下所示:
<div ng-repeat="city in cities | filter : cityFilter"></div>
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"]
在您的示例中,所有城市密钥共享相同的模式:country
+/
+city
。您的过滤器都与这些名称的城市
部分完全匹配
如果您的数据中确定了这一点(可能不是…),您可以通过创建每个过滤器条目存储每个城市的地图或对象来减少代码的循环次数:
- 为每个城市名称创建一个带有条目的对象
- 使
键
成为您希望过滤器匹配的部分
- 将
值设置为原始名称
- 循环通过
过滤器
,并返回每个键的名称
这种方法总是需要一个循环通过数据,一个循环通过过滤器。对于较小的阵列大小,您不会注意到性能差异。当其中一个数组的长度为1时,您也不会注意到任何差异
再次,请注意,只有当过滤器和城市之间存在恒定关系时,这才有效
var cities=[“美国/阿伯丁”,“美国/阿比林”,“美国/阿克伦”,“美国/奥尔巴尼”,“美国/阿尔伯克基”,“中国/广州”,“中国/福州”,“中国/北京”,“中国/包头”,“中国/呼和浩特”]
var过滤器=[‘阿克伦’、‘阿尔伯克基’、‘福州’、‘包头’];
const makeMap=(arr,getKey)=>arr.reduce(
(map,x)=>Object.assign(map{
[getKey(x)]:x
}), {}
);
常量getProp=obj=>k=>obj[k];
常量getKeys=(obj,keys)=>keys.map(getProp(obj));
//取“/”后面的部分
const cityKey=c=>c.match(/\/(.*)/)[1];
const cityMap=makeMap(cities,cityKey);
const results=getKeys(城市地图、过滤器);
控制台日志(结果)代码>返回过滤器.map(el=>“USA/”+el);为什么城市的格式在城市
和过滤器
之间有所不同?如果不是这样,您可以大大简化代码。过滤器是用户输入。城市
是来自API的数据。所以,我正在尝试适应更灵活的过滤。谢谢你的回答。这是服务中的一个函数,不使用ng repeat。使用角度过滤器也不是一个选项。我不太喜欢这种方法?我一直收到filteredCities===cities
抱歉,修复了索引。如果你能解释一下你是如何来到这里的,那就太棒了?你的思维过程?再次感谢dude:)复杂性实际上是O(m*n)
(最坏的情况是,由于短路,在平均情况下更好。)