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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:16:49  来源:igfitidea点击:

Map and filter an array at the same time

javascriptarrays

提问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.reducefor 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 页面:

flatMapcan 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 reducewith 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

使用Array.prototy.filter本身

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 mapand filterfunctions. It would work like a filter, except instead of returning true or false, it would return any object or a null/undefined.

但是,如果有一个malter()orfap()函数结合了mapandfilter函数,那就太好了。它会像过滤器一样工作,除了返回 true 或 false 之外,它会返回任何对象或 null/undefined。

回答by Stephen Quan

I optimized the answers with the following points:

我用以下几点优化了答案:

  1. Rewriting if (cond) { stmt; }as cond && stmt;
  2. Use ES6 Arrow Functions
  1. 重写if (cond) { stmt; }cond && stmt;
  2. 使用 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;
}, []);

arrwill now contain the filtered objects.

arr现在将包含过滤的对象。