我有两个数组:hobbieList和hobbieTypes。我想在hobbieTypes数组中分离hobbieList中的元素,具体取决于它们的索引值。像这样:
hobbieList = ["Rock", "Pop", "Surf", "Blues", "Soccer"];
hobbieTypes= ["music", "music", "sport", "music", "sport"];
...所以使用命令式编程和使用fors的典型应用程序将是:
let musicHobbies = [];
for(let i=0;i<hobbieList.length;i++){
if(hobbieTypes[i] === "music"){
musicHobbies.push(hobbieList[i]);
}
}
// Now "musicHobbies" has only the hobbies which type is "music".
但我希望通过函数式编程,使用 map()函数来做到这一点,并尽量保持代码尽可能简短有效。像这样:
let musicHobbies =
hobbieList.map( (elem, ind) => (hobbieTypes[ind] === "music") ? elem : null;
我觉得它看起来不错,但是有一个问题:空位置没有被删除,因此数组显示“null”,其中条件不满足。
我可以进入的第二个apporach,它工作得很好,但我不知道它是否是以功能方式编码的正确方法,是这样的:
let musicHobbies = [];
rawHobbies.map( (elem, ind) => (hobbiesTypes[ind] === "music") ? musicHobbies.push(elem) : elem);
这是第二个解决方案,设计得很好吗?或者我应该改变什么?而且,我应该使用map()函数返回的数组(如案例1),或者如果我只是将结果放在外部数组中(如情况2),那么它是否正常?
感谢您的帮助!
编辑:
这种其他方法呢?
rawHobbies.map( (elem, ind) => {
switch(hobbiesTypes[ind]){
case "music": this.hobbies.music.push(elem); break;
case "plan": this.hobbies.plans.push(elem); break;
case "hobbie": this.hobbies.hobbies.push(elem); break;
}
});
我想我会用forEach做得更好。你认为我应该使用它,使用forEach,或做这样的事情......?
this.hobbies.music = rawHobbies.filter( (x,i) => hobbieTypes[i] == "music");
this.hobbies.plans = rawHobbies.filter( (x,i) => hobbieTypes[i] == "plan");
this.hobbies.hobbies = rawHobbies.filter( (x,i) => hobbieTypes[i] == "hobbie");
我不确定这些选项中的哪一个会发挥最佳效果。意见?
编辑2:
我最终使用命令式编程来实现性能,但是感谢大家对函数式编程可以使用的不同方法。我的最终解决方案只是一个简单的foor循环:
for(let i=0;i<rawHobbies.length;i++){
switch(hobbiesTypes[i]){
case "music": this.hobbies.music.push(rawHobbies[i]); break;
case "plan": this.hobbies.plans.push(rawHobbies[i]); break;
case "hobbie": this.hobbies.hobbies.push(rawHobbies[i]); break;
}
}
答案 0 :(得分:4)
编辑后,看起来你想要更像groupBy的东西。
您可以使用.reduce()
实现这一目标。这对你有用:
const hobbieList = ["Rock", "Pop", "Surf", "Blues", "Soccer"];
const hobbieTypes= ["music", "music", "sport", "music", "sport"];
var groupedHobbies = hobbieTypes.reduce( (acc, item, index) => {
acc[item] = [...(acc[item] || []), hobbieList[index]];
return acc;
}, {});
console.log(groupedHobbies);
&#13;
通常,您希望尽可能减少副作用,并且不要在地图功能上同时执行大量操作(应将每个元素映射/转换/转换为新的元素,而不更改原始元素)。通过使用小函数,您可以在以后将它们组合起来(如果您继续遵循功能方法,您可能会阅读更多相关内容)
我建议您使用.filter()
方法而不是.map()
。
类似的东西:
hobbieList.filter((elem, ind) => hobbieTypes[ind] === "music")
将返回一个如下数组:
[
"Rock",
"Pop",
"Blues"
]
答案 1 :(得分:3)
我只想使用filter()
方法:
const hobbieList = ["Rock", "Pop", "Surf", "Blues", "Soccer"];
const hobbieTypes = ["music", "music", "sport", "music", "sport"];
console.log(hobbieList.filter((x, i) => hobbieTypes[i] === "music"));
至于您的修改:我认为使用filter()
比map()
(您实际使用forEach()
更清晰)更清晰。这可能不是最快的方式,但它肯定更有用。
答案 2 :(得分:2)
您似乎想要做的是按类型分组爱好。这个分组过程的输出应该是什么?为每种类型创建业余爱好列表的单独变量的可扩展性不是很高。创建一个对象,其键是类型,并且其值是该类型的爱好列表,这样会更好:
hobbiesByType = {
music: ["Rock", "Pop", "Blues"],
sport: ["Surf", "Soccer"]
};
现在我可以将所有音乐爱好称为hobbiesByType.music
。
此分组流程的输入应该是什么?目前,您有两个并行数组:
hobbieList = ["Rock", "Pop", "Surf", "Blues", "Soccer"];
hobbieTypes= ["music", "music", "sport", "music", "sport"];
但这不是表示此信息的最佳方式。任何时候我想检查一下,我必须引用两个数组。我可能不得不并行迭代它们。拥有单个表示会更好,而通常的方法是对象数组:
hobbies = [
{name: "Rock", type: "music"},
...
];
现在让我们考虑如何进行分组。你会在这里找到很多关于SO的例子和方法。这是一个非常基本的使用for循环:
var hobbiesByType = {};
for (var i = 0; i < hobbies.length; i++) {
var hobby = hobbies[i];
var hobbyName = hobby.name;
var hobbyType = hobby.type;
if (!(hobbyType in hobbiesByType)) hobbiesByType[hobbyType] = [];
hobbiesByType[hobbyType].push(hobby.name);
}
但你想使用&#34; functional&#34;数组方法。以上最紧凑的形式将使用reduce
,并且如下所示:
hobbiesByType = hobbies.reduce((result, hobby) => {
if (!(hobby.type in result)) result[hobby.type] = [];
result[hobby.type].push(hobby.name);
return result;
}, {});
那是所有ES5,而不是ES6。您可以使用ES6参数解构来简化它:
hobbiesByType = hobbies.reduce((result, type, name}) => {
(result[type] = result[type] || []).push(name);
return result;
}, {});
但是,不是在每种类型下创建业余爱好的名称的数组,而是自己创建业余爱好对象的数组可能更好。然后,如果爱好曾经包含其他信息 - 或许skillLevel
- 那么您可以轻松地从分组表示中进行访问。
顺便说一句,单数形式是&#34;业余爱好&#34;而不是&#34; hobbie&#34;。
答案 3 :(得分:2)
使用变量数据作为对象键将是对象的可怕滥用。相反,Map可以为您想要的数据做出更好的选择。
zip
功能与Array.prototype.reduce
组合将产生非常实用的结果
let hobbyList = ["Rock", "Pop", "Surf", "Blues", "Soccer"]
let hobbyTypes= ["music", "music", "sport", "music", "sport"]
const zip = ([x,...xs], [y,...ys]) => {
if (x === undefined || y === undefined)
return []
else
return [[x,y], ...zip(xs, ys)]
}
let result = zip(hobbyTypes, hobbyList).reduce((acc, [type, hobby]) => {
if (acc.has(type))
return acc.set(type, [...acc.get(type), hobby])
else
return acc.set(type, [hobby])
}, new Map())
console.log(result.get('music'))
// => [ 'Rock', 'Pop', 'Blues' ]
console.log(result.get('sport'))
// => [ 'Surf', 'Soccer' ]
如果确实必须使用某个对象,但实际上不应该使用,则可以使用map.entries
和Array.from
来执行此操作。
Array.from(result.entries())
.reduce((acc, [type, hobbies]) =>
Object.assign(acc, { [type]: hobbies }), {})
// => { music: [ 'Rock', 'Pop', 'Blues' ], sport: [ 'Surf', 'Soccer' ] }
答案 4 :(得分:1)
Map用于转换其他内容,而不是获取符合条件的元素。在这种情况下,您必须使用过滤功能。