同时映射和过滤数组

IT技术 javascript arrays
2021-01-24 01:37:30

我有一个对象数组,我想迭代这些对象以生成一个新的过滤数组。而且,我需要根据参数从新数组中过滤掉一些对象。我正在尝试这个:

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

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

6个回答

你应该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>


或者,reducer 可以是一个纯函数,像这样

var reduced = options.reduce(function(result, option) {
  if (option.assigned) {
    return result.concat({
      name: option.name,
      newProperty: 'Foo'
    });
  }
  return result;
}, []);
是的,现在很纯洁。+1 表示您的努力。并不是说我是纯粹的函数式编程倡导者,远非如此,我只是看不到重点:) 但实际上我在看到它后使用了你的技巧,因为它在给定的情况下非常方便。但是对于这个任务,你可能想看看 flatMap 函数,我认为在你回答之后它就变成了标准(也因为这个原因,某些浏览器可能不支持)。它应该具有更高的性能,因为像这样连接数组会使 O(n^2) 任务脱离 O(n) 任务。
2021-03-16 01:37:30
@Marko 我也介绍了一个纯减速器。PTAL。
2021-03-17 01:37:30
@MarkoflatMap不能在这里使用,因为它不允许我们进行过滤。除非,在这种情况下我们返回一个空数组。我相信这对读者来说并不容易。
2021-03-30 01:37:30
对我来说,第一个参数filtered是一个对象。所以filtered.push对我来说是未定义的。
2021-04-09 01:37:30
我也遇到了filtered成为对象的问题这是因为我没有传入“初始值” []——reduce 函数之后的空数组 ( )。例如不 var reduced = options.reduce(function(filtered, option) { ... }); 正确 var reduced = options.reduce(function(filtered, option) { ... }, []);
2021-04-12 01:37:30

自 2019 年以来,Array.prototype.flatMap是不错的选择。

options.flatMap(o => o.assigned ? [o.name] : []);

从上面链接的 MDN 页面:

flatMap可用作在地图期间添加和删除项目(修改项目数量)的一种方式。换句话说,它允许您将多个项目映射到多个项目(通过分别处理每个输入项目),而不是始终一对一。从这个意义上说,它的工作原理与过滤器相反。只需返回一个 1 元素数组来保留项目,一个多元素数组来添加项目,或者一个 0 元素数组来删除项目。

我比较了使用 jsbench.me 和 jsben.ch 并得到了非常不同的结果。第一次 flatMap 慢了 5 倍,第二次它快了 2 倍。所以我不知道如何对其进行基准测试。
2021-03-13 01:37:30
这在性能方面与使用 2 个循环(通过分别调用 array.filter 和 array.map)相比如何?
2021-03-27 01:37:30

使用减少,卢克!

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

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

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

这种方式很好,但这个问题是映射并同时过滤数组最好的方法是options.reduce(res,options....回答@Zuker
2021-03-25 01:37:30
这并不完全正确,因为在这里您丢失了初始值所在的索引,并且该信息在运行地图 fn 时非常有用。
2021-03-26 01:37:30
@hogan 但这是原始查询的正确答案(可能不是最佳解决方案)
2021-03-31 01:37:30
@vikramvi 感谢您的留言。问题是,我们可以通过多种方式实现相同的目标,而我更喜欢最好的一种。
2021-04-04 01:37:30

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

好东西。我花了一秒钟才意识到发生了什么...assigned ? [name] : []- 它可能更具可读性...(assigned ? [name] : [])
2021-03-16 01:37:30
真的很好@Maxim!我赞成这个!但是......在添加的每个元素上,它必须将所有元素传播到result......就像filter(assigned).map(name)解决方案
2021-03-29 01:37:30