将包含对象的数组展平为 1 个对象

Posted

技术标签:

【中文标题】将包含对象的数组展平为 1 个对象【英文标题】:Flatten array with objects into 1 object 【发布时间】:2015-09-17 03:22:40 【问题描述】:

给定输入:

[ a: 1 ,  b: 2 ,  c: 3 ]

如何退货:

 a: 1, b: 2, c: 3 

对于带有 lodash 的数组 it's not a problem,但这里我们有对象数组。

【问题讨论】:

可以在 SO 上询问 npm 包吗? 没有。您可以像刚才那样描述您遇到的问题,如果答案恰好是“安装此 npm 包”,那很好;但你不应该专门要求一个包来解决问题。 【参考方案1】:

使用Object.assign:

let merged = Object.assign(...arr); // ES6 (2015) syntax

var merged = Object.assign.apply(Object, arr); // ES5 syntax

请注意,Object.assign 尚未在许多环境中实现,您可能需要对其进行 polyfill(使用 core-js、另一个 polyfill 或使用 MDN 上的 polyfill)。

您提到了 lodash,因此值得指出的是,它带有一个 _.assign 函数,用于此目的,它做同样的事情:

 var merged = _.assign.apply(_, [ a: 1 ,  b: 2 ,  c: 3 ]);

但我真的推荐新的标准库方式。

【讨论】:

你不应该Object.assign(, ...arr)吗?! @Bergi 如果我想完整地保留assign 的输入,我可以。如果我不这样做,我当然不必。因为这不是一个要求,所以我没有这样对待它。 @BenjaminGruenbaum:是的,保留输入是一种最佳做法 :-) 它可能会在意外时导致丑陋的错误。 如果我没有添加额外的 ,我的 linter 会抛出 Expected at least 1 arguments, but got 0 or more.Object.assign(, ...ids.【参考方案2】:

这是一个不使用 ES6 方法的版本...

var arr = [ a: 1 ,  b: 2 ,  c: 3 ];
var obj = ;

for(var i = 0; i < arr.length; i++) 
    var o = arr[i];
    for(var key in o) 
        if(typeof o[key] != 'function')
            obj[key] = o[key];
        
    


console.log(obj);

小提琴:http://jsfiddle.net/yaw3wbb8/

【讨论】:

请注意,这也会复制可枚举的原型属性(在这种特殊情况下这不是问题)。 是否可以在 if 语句中添加一个简单的 `&& !o.propertyIsEnumerable(key)` 来解决这个问题? 好吧,for... in 仅枚举可枚举的属性。 Object(o).hasOwnProperty(obj) 会修复它(确保它不在原型上) - Object(o) 部分是为了确保我们没有调用不存在的方法,例如传递 4 不会失败(并且不复制任何内容)。 可枚举的属性不是您想要复制的吗?例如,您不希望对象中有类似Array.prototype.length 的东西.. 对吗?还是我完全错过了这个? @BenjaminGruenbaum:更好的是:Object.prototype.hasOwnProperty.call(o, i) 以确保我们不会调用自定义方法甚至非函数属性值。【参考方案3】:

你可以像这样使用 underscore.extend 函数:

var _ = require('underscore');
var a = [ a: 1 ,  b: 2 ,  c: 3 ];

var result = _.extend.apply(null, a);
console.log(result); //  a: 1, b: 2, c: 3 
console.log(a); // [  a: 1, b: 2, c: 3 ,  b: 2 ,  c: 3  ]

为了防止修改原始数组,您应该使用

var _ = require('underscore');
var a = [ a: 1 ,  b: 2 ,  c: 3 ];

var result = _.extend.apply(null, [].concat(a));
console.log(result); //  a: 1, b: 2, c: 3 
console.log(a); // [  a: 1 ,  b: 2 ,  c: 3  ]

Here can test it

【讨论】:

【参考方案4】:

我有一个不需要 polyfill 的简洁小解决方案。

var arr = [ a: 1 ,  b: 2 ,  c: 3 ];
var object = ;

arr.map(function(obj)
    var prop = Object.getOwnPropertyNames(obj);
    object[prop] = obj[prop];
);

希望有帮助:)

【讨论】:

我不知道为什么这被赞成,因为它不能不起作用 - getOwnPropertyNames 返回一个数组。 这只是偶然的,因为所有对象都有一个属性,toString使用单个属性的数组给出相同的结果,尝试向其中一个对象添加属性并看到它失败: jsfiddle.net/zqvhceyj @BenjaminGruenbaum 我完全理解 - 我只是将解决方案应用于用例。我可以更笼统,但问题明确要求“对于 this 输入,返回 this 输出”,我只是这样做。 @Jonathan***s 这正是我所要求的。 :-) @Ultra 哈哈!这就是我从你的问题中收集到的;我很高兴我的反对票是没有根据的:')【参考方案5】:

有了lodash,你可以使用merge():

var arr = [  a: 1 ,  b: 2 ,  c: 3  ];
_.merge.apply(null, [].concat(arr));
// →  a: 1, b: 2, c: 3 

如果您在多个地方这样做,您可以使用partial() 和spread() 使merge() 更加优雅:

var merge = _.spread(_.partial(_.merge, ));
merge(arr);
// →  a: 1, b: 2, c: 3 

【讨论】:

【参考方案6】:

这是Object.assignarray.prototype.reduce 函数的一个很好的用法:

let merged = arrOfObjs.reduce((accum, val) => 
  Object.assign(accum, val);
  return accum;
, )

这种方法不会改变输入的对象数组,这可以帮助您避免难以解决的问题。

【讨论】:

在转换为其他类型的对象时很有用【参考方案7】:

您可以轻松地将对象扁平化为数组。

function flatten(elements) 
  return elements.reduce((result, current) => 
    return result.concat(Array.isArray(current) ? flatten(current) : current);
  , []);
;

【讨论】:

【参考方案8】:

除了已接受的答案之外,还有一个运行 ES6 的代码 sn-p。

let input = [ a: 1 ,  b: 2 ,  c: 3 ]
//Get input object list with spread operator
console.log(...input)
//Get all elements in one object
console.log(Object.assign(...input))

【讨论】:

【参考方案9】:

在提出这个问题 6 年后。

Object.assign 是我最喜欢的答案(上图)。

但这也合法吗?

let res = ;
[ a: 1 ,  b: 2 ,  c: 3 ].forEach(val => 
    let key = Object.keys(val);
    console.log(key[0]);
    res[key] = val[key];
)

【讨论】:

以上是关于将包含对象的数组展平为 1 个对象的主要内容,如果未能解决你的问题,请参考以下文章

雪花中具有多个 JSON 对象的横向展平数组

如何将 JSON 对象展平为 Pandas Dataframe 对象 [重复]

使用 jq 保留键名展平 JSON

对表格多数组的环回响应/将对象的嵌套数组展平为线性数组

展平 Python 列表而不创建任何对象的副本?

仅将 java 类实例转换为原始类型