Javascript 同时映射和过滤数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34398279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Map and filter an array at the same time
提问by Daniel Calderon Mori
I have an array of objects that I want to iterate over to produce a new filtered array. But also, I need to filter out some of the objects from the new array depending of a parameter. I'm trying this:
我有一个对象数组,我想迭代这些对象以生成一个新的过滤数组。而且,我需要根据参数从新数组中过滤掉一些对象。我正在尝试这个:
function renderOptions(options) {
return options.map(function (option) {
if (!option.assigned) {
return (someNewObject);
}
});
}
Is that a good approach? Is there a better method? I'm open to use any library such as lodash.
这是一个好方法吗?有没有更好的方法?我愿意使用任何库,例如 lodash。
回答by thefourtheye
You should use Array.reduce
for this.
你应该Array.reduce
为此使用。
var options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
var reduced = options.reduce(function(filtered, option) {
if (option.assigned) {
var someNewValue = { name: option.name, newProperty: 'Foo' }
filtered.push(someNewValue);
}
return filtered;
}, []);
document.getElementById('output').innerHTML = JSON.stringify(reduced);
<h1>Only assigned options</h1>
<pre id="output"> </pre>
Alternatively, the reducer can be a pure function, like this
或者,reducer 可以是一个纯函数,像这样
var reduced = options.reduce(function(result, option) {
if (option.assigned) {
return result.concat({
name: option.name,
newProperty: 'Foo'
});
}
return result;
}, []);
回答by Zuker
Use reduce, Luke!
使用减少,卢克!
function renderOptions(options) {
return options.reduce(function (res, option) {
if (!option.assigned) {
res.push(someNewObject);
}
return res;
}, []);
}
回答by Trevor Dixon
Since 2019, Array.prototype.flatMapis good option.
自 2019 年以来,Array.prototype.flatMap是不错的选择。
options.flatMap(o => o.assigned ? [o.name] : []);
From the MDN page linked above:
从上面链接的 MDN 页面:
flatMap
can be used as a way to add and remove items (modify the number of items) during a map. In other words, it allows you to map many items to many items (by handling each input item separately), rather than always one-to-one. In this sense, it works like the opposite of filter. Simply return a 1-element array to keep the item, a multiple-element array to add items, or a 0-element array to remove the item.
flatMap
可用作在地图期间添加和删除项目(修改项目数量)的一种方式。换句话说,它允许您将多个项目映射到多个项目(通过分别处理每个输入项目),而不是始终一对一。从这个意义上说,它的工作原理与过滤器相反。只需返回一个 1 元素数组来保留项目,一个多元素数组来添加项目,或者一个 0 元素数组来删除项目。
回答by Natividad Lara Diaz
With ES6 you can do it very short:
使用 ES6,你可以做到很短:
options.filter(opt => !opt.assigned).map(opt => someNewObject)
options.filter(opt => !opt.assigned).map(opt => someNewObject)
回答by Maxim Kuzmin
One line reduce
with ES6 fancy spread syntaxis here!
一行reduce
带有 ES6 花式展开语法的代码就在这里!
var options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
const filtered = options
.reduce((result, {name, assigned}) => [...result, ...assigned ? [name] : []], []);
console.log(filtered);
回答by matsve
I'd make a comment, but I don't have the required reputation. A small improvement to Maxim Kuzmin's otherwise very good answer to make it more efficient:
我会发表评论,但我没有所需的声誉。对马克西姆·库兹明 (Maxim Kuzmin) 的其他非常好的答案进行了小幅改进,使其更有效率:
const options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
const filtered = options
.reduce((result, { name, assigned }) => assigned ? result.concat(name) : result, []);
console.log(filtered);
Explanation
解释
Instead of spreading the entire result over and over for each iteration, we only append to the array, and only when there's actually a value to insert.
我们不是在每次迭代中一遍又一遍地传播整个结果,而是只附加到数组中,并且仅在实际需要插入值时才附加。
回答by AmmarCSE
Use Array.prototy.filteritself
function renderOptions(options) {
return options.filter(function(option){
return !option.assigned;
}).map(function (option) {
return (someNewObject);
});
}
回答by Daniel
At some point, isn't it easier(or just as easy) to use a forEach
在某些时候,是不是更容易(或同样容易)使用 forEach
var options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
var reduced = []
options.forEach(function(option) {
if (option.assigned) {
var someNewValue = { name: option.name, newProperty: 'Foo' }
reduced.push(someNewValue);
}
});
document.getElementById('output').innerHTML = JSON.stringify(reduced);
<h1>Only assigned options</h1>
<pre id="output"> </pre>
However it would be nice if there was a malter()
or fap()
function that combines the map
and filter
functions. It would work like a filter, except instead of returning true or false, it would return any object or a null/undefined.
但是,如果有一个malter()
orfap()
函数结合了map
andfilter
函数,那就太好了。它会像过滤器一样工作,除了返回 true 或 false 之外,它会返回任何对象或 null/undefined。
回答by Stephen Quan
I optimized the answers with the following points:
我用以下几点优化了答案:
- Rewriting
if (cond) { stmt; }
ascond && stmt;
- Use ES6 Arrow Functions
- 重写
if (cond) { stmt; }
为cond && stmt;
- 使用 ES6箭头函数
I'll present two solutions, one using forEach, the other using reduce:
我将介绍两种解决方案,一种使用forEach,另一种使用reduce:
Solution 1: Using forEach
解决方案 1:使用 forEach
var options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
var reduced = []
options.forEach(o => {
o.assigned && reduced.push( { name: o.name, newProperty: 'Foo' } );
} );
console.log(reduced);
Solution 2: Using reduce
解决方案2:使用reduce
var options = [
{ name: 'One', assigned: true },
{ name: 'Two', assigned: false },
{ name: 'Three', assigned: true },
];
var reduced = options.reduce((a, o) => {
o.assigned && a.push( { name: o.name, newProperty: 'Foo' } );
return a;
}, [ ] );
console.log(reduced);
I leave it up to you to decide which solution to go for.
我让你来决定采用哪种解决方案。
回答by Bhargav Ponnapalli
Using reduce, you can do this in one Array.prototype function. This will fetch all even numbers from an array.
使用reduce,您可以在一个Array.prototype 函数中完成此操作。这将从数组中获取所有偶数。
var arr = [1,2,3,4,5,6,7,8];
var brr = arr.reduce((c, n) => {
if (n % 2 !== 0) {
return c;
}
c.push(n);
return c;
}, []);
document.getElementById('mypre').innerHTML = brr.toString();
<h1>Get all even numbers</h1>
<pre id="mypre"> </pre>
You can use the same method and generalize it for your objects, like this.
您可以使用相同的方法并将其概括为您的对象,如下所示。
var arr = options.reduce(function(c,n){
if(somecondition) {return c;}
c.push(n);
return c;
}, []);
arr
will now contain the filtered objects.
arr
现在将包含过滤的对象。