【问题标题】:Get union of keys of all objects in js array using reduce使用reduce获取js数组中所有对象的键的联合
【发布时间】:2016-10-21 19:28:44
【问题描述】:

假设,我们有:

var all=[
    {firstname:'Ahmed', age:12},
    {firstname:'Saleh', children:5 }
    {fullname: 'Xod BOD', children: 1}
];

预期结果是['firstname','age', 'children', 'fullname']:该数组所有对象的键的联合:

all.map((e) => Object.keys(e) ).reduce((a,b)=>[...a,...b],[]); 

这很好,但是,我正在寻求一个解决方案,使用直接使用 reduce 方法而不使用 map 的性能更高,我做了以下操作,但失败了。

all.reduce((a,b) =>Object.assign([...Object.keys(a),...Object.keys(b)]),[])

【问题讨论】:

  • codereview 上发布可能更好,但Object.keys(Object.assign({}, ...all)) 是一种选择。我对性能一无所知。

标签: javascript arrays performance functional-programming


【解决方案1】:

您可以使用Setreduce()Object.keys(),不需要地图。

var all=[
  {firstname:'Ahmed', age:12},
  {firstname:'Saleh', children:5 },
  {fullname: 'Xod BOD', children: 1}
];

var result = [...new Set(all.reduce((r, e) => [...r, ...Object.keys(e)], []))];
console.log(result)

【讨论】:

  • 为什么是Set?你的all.reduce((r, e) => r.concat(Object.keys(e)), []) 已经给出了一个数组。
【解决方案2】:

这是一个使用通用过程 concatflatMap 和 ES6 Set 的解决方案。

它类似于@NenadVracar 的解决方案,但使用了高阶函数,而不是复杂的、多合一的实现。这降低了转换的复杂性,并且可以更轻松地在程序的其他区域重用过程。

并不是说... 传播语法不好,但您也会注意到此解决方案不需要它。

var all = [
  {firstname:'Ahmed', age:12},
  {firstname:'Saleh', children:5 },
  {fullname: 'Xod BOD', children: 1}
];

const concat = (x,y) => x.concat(y);

const flatMap = f => xs => xs.map(f).reduce(concat, []);

const unionKeys = xs =>
  Array.from(new Set(flatMap (Object.keys) (xs)));

console.log(unionKeys(all));
// [ 'firstname', 'age', 'children', 'fullname' ]

【讨论】:

    【解决方案3】:

    出于好奇,我一直在使用不同的方法(reduce vs foreach vs set)对您的问题的一些解决方案进行基准测试。看起来 Set 对于小型数组表现良好,但对于较大的数组来说非常慢(这是 foreach 的最佳解决方案)。

    希望对你有帮助。

    var all = [{
        firstname: 'Ahmed',
        age: 12
      }, {
        firstname: 'Saleh',
        children: 5
      }, {
        fullname: 'Xod BOD',
        children: 1
      }],
      result,
      res = {};
    
    const concat = (x,y) => x.concat(y);
    
    const flatMap = f => xs => xs.map(f).reduce(concat, []);
    
    const unionKeys = xs =>
      Array.from(new Set(flatMap (Object.keys) (xs)));
    
    for(var i = 0; i < 10; i++)
      all = all.concat(all);
    
    console.time("Reduce");
    result = Object.keys(all.reduce((memo, obj) => Object.assign(memo, obj), {}));
    console.timeEnd("Reduce");
    
    console.time("foreach");
    all.forEach(obj => Object.assign(res, obj));
    result = Object.keys(res);
    console.timeEnd("foreach");
    
    console.time("Set");
    result = [...new Set(all.reduce((r, e) => r.concat(Object.keys(e)), []))];
    console.timeEnd("Set");
    
    console.time("Set2");
    result = unionKeys(all);
    console.timeEnd("Set2");

    【讨论】:

    • 你不应该使用{}作为备忘录。对于这种事情,请使用SetMap
    • @naomik 正如你在帖子中看到的,我正在测试一些实现的性能,其中一个使用 Set
    • 您没有使用Set 作为备忘录,所以您的比较几乎完全没有意义。 Set 仅用于从结果中删除非唯一值。
    【解决方案4】:

    试试这个代码:

    var union = new Set(getKeys(all));
    
    console.log(union);
    // if you need it to be array
    console.log(Array.from(union));
    
    //returns the keys of the objects inside the collection
    function getKeys(collection) {
        return collection.reduce(
            function(union, current) {
                if(!(union instanceof Array)) {
                    union = Object.keys(union);
                }
                return union.concat(Object.keys(current));
            });
    }
    

    【讨论】:

    • 这是一项英勇的努力,但 addToSet 变异了 set,这在函数式程序中通常是不明智的。
    • @naomik 你所说的“变异set”是什么意思? set 在这里只是一个变量。
    • @naomik 为什么在这种特殊情况下这样做是一件坏事?
    • 函数式编程的目标是创建纯函数——突变应该以一种允许函数运行而不会产生副作用的方式进行本地化。
    • @naomik 谢谢你的评论,检查我的编辑,我试图删除这个缺陷(:
    猜你喜欢
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2020-02-16
    • 2022-11-11
    • 2021-10-27
    • 1970-01-01
    • 2020-11-11
    • 2017-02-17
    相关资源
    最近更新 更多