同时映射和过滤数组

时间:2015-12-21 14:43:14

标签: javascript arrays

我有一个对象数组,我想迭代生成一个新的过滤数组。但是,我还需要根据参数从新数组中过滤掉一些对象。我试过这个:

function renderOptions(options) {
    return options.map(function (option) {
        if (!option.assigned) {
            return (someNewObject);
        }
    });   
}

这是一个好方法吗?有更好的方法吗?我打开使用任何库,例如lodash。

12 个答案:

答案 0 :(得分:118)

您应该使用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>

更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

答案 1 :(得分:38)

使用reduce,Luke!

function renderOptions(options) {
    return options.reduce(function (res, option) {
        if (!option.assigned) {
            res.push(someNewObject);
        }
        return res;
    }, []);   
}

答案 2 :(得分:14)

使用ES6,你可以做得很短:

options.filter(opt => !opt.assigned).map(opt => someNewObject)

答案 3 :(得分:5)

ES6花式spread syntax的一行reduce就在这里!

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);

答案 4 :(得分:3)

使用Array.prototy.filter本身

function renderOptions(options) {
    return options.filter(function(option){
        return !option.assigned;
    }).map(function (option) {
        return (someNewObject);
    });   
}

答案 5 :(得分:3)

Array.prototype.flatMap是另一种选择。

const options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];
options.flatMap(o => o.assigned ? o.name : []);
// ['One', 'Three']

从上面链接的MDN页面上:

  

flatMap可用作添加和删除项目的方法(修改   地图中的项数)。换句话说,它允许您映射   许多项目到许多项目(通过分别处理每个输入项目),   而不是总是一对一的。从这个意义上讲,它就像   过滤器的对面。只需返回一个1元素数组即可保留该项目,   一个多元素数组以添加项目,或一个0元素数组以删除项目   该项目。

答案 6 :(得分:1)

使用reduce,您可以在一个Array.prototype函数中执行此操作。这将从数组中获取所有偶数。

var arr = [1,2,3,4,5,6,7,8];

var brr  = arr.reduce(function(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>

您可以使用相同的方法并将其概括为您的对象,例如:

var arr = options.reduce(function(c,n){
  if(somecondition){return c;}
  c.push(n); return c;
},[]);

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

答案 7 :(得分:1)

在某些时候,使用forEach

更容易(或同样容易)

&#13;
&#13;
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);
&#13;
<h1>Only assigned options</h1>
<pre id="output"> </pre>
&#13;
&#13;
&#13;

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

答案 8 :(得分:1)

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

  1. if (cond) { stmt; }重写为cond && stmt;
  2. 使用ES6 Arrow Functions
  3. 我将提供两个解决方案,一个使用forEach,另一个使用reduce

    解决方案1:使用forEach

    &#13;
    &#13;
    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);
    &#13;
    &#13;
    &#13;

    解决方案2:使用reduce

    &#13;
    &#13;
    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);
    &#13;
    &#13;
    &#13;

    我可以决定选择哪种解决方案。

答案 9 :(得分:1)

我要发表评论,但我没有所需的声誉。对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);

说明

我们不会在每次迭代中一遍又一遍地散布整个结果,而是仅在实际有要插入的值时才追加到数组。

答案 10 :(得分:0)

直接使用.reduce可能很难读懂,所以我建议创建一个为您生成减速器的函数:

function mapfilter(mapper) {
  return (acc, val) => {
    const mapped = mapper(val);
    if (mapped !== false)
      acc.push(mapped);
    return acc;
  };
}

像这样使用它:

const words = "Map and filter an array #javascript #arrays";
const tags = words.split(' ')
  .reduce(mapfilter(word => word.startsWith('#') && word.slice(1)), []);
console.log(tags);  // ['javascript', 'arrays'];

答案 11 :(得分:0)

你可以使用带有箭头函数的 Array.reduce 是一行代码

const options = [
  { name: 'One', assigned: true }, 
  { name: 'Two', assigned: false }, 
  { name: 'Three', assigned: true }, 
];

const reduced = options.reduce((result, option) => option.assigned ? result.concat({ name: option.name, newProperty: 'Foo' }) : result, []);

document.getElementById('output').innerHTML = JSON.stringify(reduced);
<h1>Only assigned options</h1>
<pre id="output"> </pre>

相关问题