将数组转换为对象


514

转换的最佳方法是什么:

['a','b','c']

至:

{
  0: 'a',
  1: 'b',
  2: 'c'
}

3
也许他需要的是一些鸭子式​​代码,不要认为它是一个数组实例
Pointy 2010年

6
值得指出的是Javascript数组对象。
Spudley

如果有人在寻找Lodash解决方案,请考虑一下_.keyBy(以前_.indexBy):lodash.com/docs#keyBy
2540625

这有点令人困惑,因为数组已经是对象了,但是我想问题的重点是将数组 奇异对象转换为普通对象
Oriol

1
使用Lodash进行此操作的一种简单方法是_.toPlainObject。例如:var myObj = _.toPlainObject(myArr)
朱利安·索罗

Answers:


472

ECMAScript 6引入了易于填充的内容Object.assign

Object.assign()方法用于将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign({}, ['a','b','c']); // {0:"a", 1:"b", 2:"c"}

length数组的自身属性不会被复制,因为它不可枚举。

另外,您可以使用ES6 传播语法来达到相同的结果:

{ ...['a', 'b', 'c'] }

只是想指出-如果您已经具有原始对象的排序属性数组,则使用散布运算符将直接将数组转换为新对象:{ ...[sortedArray]}
HappyHands31,19年

Oriol,有没有办法设置固定密钥而不是0和1?
Menai Ala Eddine

488

具有这样的功能:

function toObject(arr) {
  var rv = {};
  for (var i = 0; i < arr.length; ++i)
    rv[i] = arr[i];
  return rv;
}

您的数组已经或多或少只是一个对象,但是对于整数命名属性,数组确实具有一些“有趣”的特殊行为。以上将为您提供一个简单的对象。

编辑哦,您也可能要考虑数组中的“孔”:

function toObject(arr) {
  var rv = {};
  for (var i = 0; i < arr.length; ++i)
    if (arr[i] !== undefined) rv[i] = arr[i];
  return rv;
}

在现代JavaScript运行时中,可以使用以下.reduce()方法:

var obj = arr.reduce(function(acc, cur, i) {
  acc[i] = cur;
  return acc;
}, {});

那也避免了数组中的“空洞”,因为这是.reduce()有效的。


2
@ m93a,它已经是一个对象。在JavaScript中,[]如果您不打算使用数字属性键和“ length”属性,那么创建一个Array实例()确实没有意义。
尖尖的

14
避免重新分配参数的更清洁方法const obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
huygn

3
没有显式返回的箭头+破坏语法:const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
Marc Scheib

2
@eugene_sunic确实如此,但是当我在2010年回答此问题时,该方法不可用:)
Pointy

2
正如@miro所指出的,每次创建一个新对象都是不必要的,实际上比操作创建的初始对象要慢得多。在包含1000个元素的数组上运行JSPerf测试,每次创建一个新对象的速度都比对现有对象进行突变的速度慢1000倍。jsperf.com/…–
罗勒姆

281

您可以使用累加器aka reduce

['a','b','c'].reduce(function(result, item, index, array) {
  result[index] = item; //a, b, c
  return result;
}, {}) //watch out the empty {}, which is passed as "result"

以空物体{}为起点;然后逐步“增强”该对象。在迭代结束时,result将是{"0": "a", "1": "b", "2": "c"}

如果您的数组是一组键值对对象:

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item) {
  var key = Object.keys(item)[0]; //first property: a, b, c
  result[key] = item[key];
  return result;
}, {});

将产生: {a: 1, b: 2, c: 3}

为了完整起见,reduceRight允许您以相反的顺序遍历数组:

[{ a: 1},{ b: 2},{ c: 3}].reduceRight(/* same implementation as above */)

将产生: {c:3, b:2, a:1}

您的蓄能器可以是任何特定用途的类型。例如,为了交换数组中对象的键和值,请传递[]

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item, index) {
  var key = Object.keys(item)[0]; //first property: a, b, c
  var value = item[key];
  var obj = {};
  obj[value] = key;
  result.push(obj);
  return result;
}, []); //an empty array

将产生: [{1: "a"}, {2: "b"}, {3: "c"}]

与不同mapreduce不得用作1-1映射。您完全控制要包含或排除的项目。因此reduce,您可以实现filter功能,这使得功能reduce非常广泛:

[{ a: 1},{ b: 2},{ c: 3}].reduce(function(result, item, index) {
  if(index !== 0) { //skip the first item
    result.push(item);
  }
  return result;
}, []); //an empty array

将产生: [{2: "b"}, {3: "c"}]

注意reduceObject.key是的一部分ECMA 5th edition;您应该为不支持它们的浏览器(尤其是IE8)提供一个polyfill。

查看Mozilla的默认实现。


1
使用对象地图且需要放下其中一个键时,有助于维护redux存储
dhruvpatel

101

如果您使用的是jquery:

$.extend({}, ['a', 'b', 'c']);

4
很奇怪,如果我输入一个Array变量,它将每个字符放在一个单独的对象中:0:“ a”,1:“,”,2:“ b” ...因此它忽略引号,但包含逗号。 。
TrySpace

@Max我认为没有这种行为。返回的对象是{0: 'a', 1: 'b', 2: 'c'}预期的结果。
ivkremer 2013年

3
有没有一种方法可以使用$ .extend同时以非数字方式通知键,即:对数组项进行计算?
Davi Lima 2014年

超级可怕和短期测试
Faisal Mehmood Awan

63

为了完整起见,ECMAScript 2015(ES6)不断扩展。需要使用Transpiler(Babel)或至少运行ES6的环境。

console.log(
   { ...['a', 'b', 'c'] }
)


2
实际上,这在ES2015中也不是本地可用的。但是,它非常优雅。
Aluan Haddad '18

47

我可能会这样写(因为很少有我手头没有underscorejs库):

var _ = require('underscore');

var a = [ 'a', 'b', 'c' ];
var obj = _.extend({}, a);
console.log(obj);
// prints { '0': 'a', '1': 'b', '2': 'c' }

9
您否决了我的回应,但无可奉告?我的答案是正确的并经过测试。有什么异议?
戴夫·多普森

14
这个问题没有下划线标签,并且您还假设使用node.js或require库。
David Hellsing 2012年

10
下划线在客户端和服务器上都很常见。Backbone.js假定使用它,并且可能是最常用的实用程序库。话虽如此,我包括了require行,以明确说明我正在使用一个库。没有用于描述“将underscore.js添加到您的页面”的1-liner,因此浏览器环境需要进行一些翻译
Dave Dopson

6
不过,如果您使用的是undserscore,则只需obj=_.extend({},a);做一个简单的工作即可。另外,如果您要遍历数组,我会说_.each比更为合适_.map。总而言之,这在几个层面上都不是一个好的答案。
David Hellsing

4
“您必须不加下划线或破折号就回答”的人是如此烦人。相当于说您必须回答C ++问题而不提及标准库。如果不能使用下划线或破折号,则OP应该提及。
查理·马丁

26

这是一个O(1)ES2015方法,仅出于完整性考虑。

var arr = [1, 2, 3, 4, 5]; // array, already an object
Object.setPrototypeOf(arr, Object.prototype); // now no longer an array, still an object

(1)根据MDN的说法,更改对象的[[Prototype]]是非常缓慢的操作。(2)这不会删除自己的length财产。(3)对象仍然是数组Array.isArray(arr) === true。(4)不会删除特殊的数组行为,例如,arr.length = 0删除所有索引。(5)因此,我认为Object.assign更好
Oriol

1
@Oriol mdn是错误的,至少在V8中(以及其他引擎),这在这种特殊情况下是非常快速的操作-因为对象无论如何都具有数值存储,这基本上是在改变两个指针。
本杰明·格伦鲍姆

这也可以用于以下事实:在其他快速解决方案中,它显然是唯一的,可以保留阵列上的任何非索引(“自己”)属性(即非正整数属性)...
Brett Zamir

但是,嗯,即使没有这样做也要Array.isArray返回true“对象” instanceof Array……
Brett Zamir

@BrettZamir听起来像个小虫子:D
Benjamin Gruenbaum

26

惊讶地没看到-

console.log(
  Object.assign({}, ['a', 'b', 'c'])
)


任何智能建议,创建{ "first":"a", "second":"b","third":"c" }与键固定-我要寻找一个自毁
mplungjan

@mplungjan我建议在这种情况下使用reduce而不是assign。如果需要的话,可能有一个库可以让您枚举每个序数。
威廉·贾德

今天我还有另一个案子。最后我问一个关于它的问题:stackoverflow.com/questions/62197270/destruct-using-titles/...
mplungjan

23

我们可以使用Object.assignarray.reduce函数将Array转换为Object。

var arr = [{a:{b:1}},{c:{d:2}}] 
var newObj = arr.reduce((a, b) => Object.assign(a, b), {})

console.log(newObj)


这就是我想要的。我不需要索引,我需要将数组转换为保留的键值对。
Mike K

18

我最终使用对象传播运算符,因为它是ECMAScript 2015(ES6)标准的一部分。

const array = ['a', 'b', 'c'];
console.log({...array});
// it outputs {0:'a', 1:'b', 2:'c'}

下面以小提琴为例。


1
我不确定这样做的性能,但是由于数组到对象的转换如此之多(因为我想对所有代码使用对象进行标准化),这可能是最简单的。
某人特别

与提供相同解决方案的任何现有答案相比,这如何更好?
Dan Dascalescu

17
Object.assign({}, ['one', 'two']); // {0: 'one', 1: 'two'}

在现代JavaScript中,简单的方法是使用Object.assign()它,除了将key:value从一个对象复制到另一个对象外,什么也没有做。在我们的例子中,Array将属性捐赠给new {}


与提供相同解决方案的任何现有答案相比,这如何更好?
Dan Dascalescu

丹·达斯卡斯库(Dan Dascalescu)当时我添加了答案,O.assign但上述答案仅存在于上面,但缺乏解释。如今,将数组分解为对象是一种方法({...array}
Appeiron

13

对于ES2016,对象的散布运算符。注意:这是 ES6 之后的,因此需要对Transpiler进行调整。

const arr = ['a', 'b', 'c'];
const obj = {...arr}; // -> {0: "a", 1: "b", 2: "c"} 


传播运营商的答案早在两年前就已经给出。
Dan Dascalescu


10

使用 javascript#forEach一个可以做到这一点

var result = {},
    attributes = ['a', 'b','c'];

attributes.forEach(function(prop,index) {
  result[index] = prop;
});

使用ECMA6:

attributes.forEach((prop,index)=>result[index] = prop);

10

FWIW的另一种最新方法是将新方法Object.fromEntriesObject.entries以下方法一起使用:

const arr = ['a','b','c'];
arr[-2] = 'd';
arr.hello = 'e';
arr.length = 17;
const obj = Object.fromEntries(Object.entries(arr));

...这可以避免将稀疏数组项存储为undefined或,null并保留非索引键(例如,非正整数/非数字键)。

arr.length但是,不妨增加一点,因为其中不包括:

obj.length = arr.length;


9

如果您使用的是ES6,则可以使用Object.assign和散布运算符

{ ...['a', 'b', 'c'] }

如果您有嵌套数组

var arr=[[1,2,3,4]]
Object.assign(...arr.map(d => ({[d[0]]: d[1]})))

1
不仅变量名不同,而且示例也不起作用,从构造函数创建映射最初需要2d键值数组。new Map([['key1', 'value1'], ['key2', 'value2']]);
Shannon Hochkins '17

5

快速而肮脏的一个:

var obj = {},
  arr = ['a','b','c'],
  l = arr.length; 

while( l && (obj[--l] = arr.pop() ) ){};

我想你忘了测试;它产生{0:"c", 1:"b", 2:"a"}。您要么想要unshift代替,pop要么(最好)以i=arr.length-1and减量开始。
Phrogz

是的..只是更改了它,但随后变得不那么有趣了:/
Mic

甚至可以做到l = arr.length,然后while (l && (obj[--l] = arr.pop())){}(我意识到这已经很老了,但是为什么不进一步简化它)。
Qix-蒙尼卡(Monica)

2
@Qix,缩短时间很不错
Mic

4

快速又肮脏的#2:

var i = 0
  , s = {}
  , a = ['A', 'B', 'C'];

while( a[i] ) { s[i] = a[i++] };

为什么使用逗号表示法?
康纳·鲁尔

3
个人喜好让逗号位于下一行。我发现此符号更易于阅读。
BingeBoy

1
如果数组包含错误值,则循环将停止。您应该检查i < a.length而不是a[i]
Oriol

4

从Lodash 3.0.0开始,您可以使用_.toPlainObject

var obj = _.toPlainObject(['a', 'b', 'c']);
console.log(obj);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>


3

这是我刚写的一个递归函数。这很简单,效果很好。

// Convert array to object
var convArrToObj = function(array){
    var thisEleObj = new Object();
    if(typeof array == "object"){
        for(var i in array){
            var thisEle = convArrToObj(array[i]);
            thisEleObj[i] = thisEle;
        }
    }else {
        thisEleObj = array;
    }
    return thisEleObj;
}

这是一个示例(jsFiddle):

var array = new Array();
array.a = 123;
array.b = 234;
array.c = 345;
var array2 = new Array();
array2.a = 321;
array2.b = 432;
array2.c = 543;
var array3 = new Array();
array3.a = 132;
array3.b = 243;
array3.c = 354;
var array4 = new Array();
array4.a = 312;
array4.b = 423;
array4.c = 534;
var array5 = new Array();
array5.a = 112;
array5.b = 223;
array5.c = 334;

array.d = array2;
array4.d = array5;
array3.d = array4;
array.e = array3;


console.log(array);

// Convert array to object
var convArrToObj = function(array){
    var thisEleObj = new Object();
    if(typeof array == "object"){
        for(var i in array){
            var thisEle = convArrToObj(array[i]);
            thisEleObj[i] = thisEle;
        }
    }else {
        thisEleObj = array;
    }
    return thisEleObj;
}
console.log(convArrToObj(array));

结果: 递归数组到对象


真的很好。谢谢
Hanmaslah '17

如果您拥有['a' = '1', 'b' = '2', 'c' = '3']并希望它像{a: 1, b: 2, c: 3}这样完美运行,则应该更高一些。
万家

3
.reduce((o,v,i)=>(o[i]=v,o), {})

[docs]

或更详细

var trAr2Obj = function (arr) {return arr.reduce((o,v,i)=>(o[i]=v,o), {});}

要么

var transposeAr2Obj = arr=>arr.reduce((o,v,i)=>(o[i]=v,o), {})

最短的香草香草JS

JSON.stringify([["a", "X"], ["b", "Y"]].reduce((o,v,i)=>{return o[i]=v,o}, {}))
=> "{"0":["a","X"],"1":["b","Y"]}"

一些更复杂的例子

[["a", "X"], ["b", "Y"]].reduce((o,v,i)=>{return o[v[0]]=v.slice(1)[0],o}, {})
=> Object {a: "X", b: "Y"}

甚至更短(通过使用function(e) {console.log(e); return e;}=== (e)=>(console.log(e),e)

 nodejs
> [[1, 2, 3], [3,4,5]].reduce((o,v,i)=>(o[v[0]]=v.slice(1),o), {})
{ '1': [ 2, 3 ], '3': [ 4, 5 ] }

[/ docs]


您打算做[/docs]什么?使代码片段可执行将更有用。
Dan Dascalescu

3

我会简单地用Array.of()数组可以将其上下文用作构造函数。

注2:功能是有意通用的工厂方法;它不需要其this值是Array构造函数。因此,它可以被其他构造函数传递或继承,这些构造函数可以使用单个数字参数调用。

因此,我们可以绑定Array.of()到一个函数并生成一个类似于对象的数组。

function dummy(){};
var thingy = Array.of.apply(dummy,[1,2,3,4]);
console.log(thingy);

通过利用Array.of() 甚至可以做数组子分类


3

如果可以使用MapObject.assign,则非常简单。

创建一个数组:

const languages = ['css', 'javascript', 'php', 'html'];

下面创建了一个以索引为键的对象:

Object.assign({}, languages)

使用“地图”复制与上述相同的内容

转换为基于索引的对象,{0 : 'css'}等等。

const indexMap = new Map(languages.map((name, i) => [i, name] ));
indexMap.get(1) // javascript

转换为基于值的对象{css : 'css is great'}等...

const valueMap = new Map(languages.map(name => [name, `${name} is great!`] ));
valueMap.get('css') // css is great

3

快速将项目数组转换为对象的简便方法

function arrayToObject( srcArray ){
    return  JSON.parse( JSON.stringify( srcArray ) );
}

然后像这样使用它...

var p = [0,2,3,'pork','pie',6];
obj = new arrayToObject( p );
console.log( obj[3], obj[4] )
// expecting `pork pie`

输出:

pork pie

检查类型:

typeof obj
"object"

如果没有原型方法,事情就不会完成

Array.prototype.toObject =function(){
    return  JSON.parse( JSON.stringify( this ) );
}

使用像:

var q = [0,2,3,'cheese','whizz',6];
obj = q.toObject();
console.log( obj[3], obj[4] )
// expecting `cheese whizz`

输出:

cheese whizz

*请注意,没有命名例程,因此,如果要使用特定名称,则需要继续使用下面的现有方法。


较旧的方法

这使您可以从数组生成对象,该对象具有按所需顺序定义的键。

Array.prototype.toObject = function(keys){
    var obj = {};
    var tmp = this; // we want the original array intact.
    if(keys.length == this.length){
        var c = this.length-1;
        while( c>=0 ){
            obj[ keys[ c ] ] = tmp[c];
            c--;
        }
    }
    return obj;
};

result = ["cheese","paint",14,8].toObject([0,"onion",4,99]);

console.log(">>> :" + result.onion); 将输出“ paint”,该函数必须具有相等长度的数组,否则您将得到一个空对象。

这是一种更新的方法

Array.prototype.toObject = function(keys){
    var obj = {};
    if( keys.length == this.length)
        while( keys.length )
            obj[ keys.pop() ] = this[ keys.length ];
    return obj;
};

这不仅破坏了key数组的内容,而且破坏了内部数组,也破坏了values数组(其内容)。JavaScript与PHP的工作方式不同,JavaScript通过引用对象/数组的属性自动作用。
布雷特·扎米尔

不,不是这样,例程会进行复印,不会触碰原始文件。
Mark Giblin 2014年

是的,原稿被触摸。参见jsfiddle.net/bRTv7。所述阵列的长度最终两者都是0。
布雷特扎米尔

好的,我刚刚对其进行更改的编辑版本不会破坏数组,发现它本来应该做的很奇怪。
Mark Giblin

1
更新的方法应该在旧的浏览器如JSON已经有超过ECMA添加新的代码功能的支持
马克·吉布林

2

let i = 0;
let myArray = ["first", "second", "third", "fourth"];

const arrayToObject = (arr) =>
    Object.assign({}, ...arr.map(item => ({[i++]: item})));

console.log(arrayToObject(myArray));

或使用

myArray = ["first", "second", "third", "fourth"]
console.log({...myArray})


2

ES5-解决方案:

使用数组原型函数“ push”“ apply”,可以使用数组元素填充对象。

var arr = ['a','b','c'];
var obj = new Object();
Array.prototype.push.apply(obj, arr);
console.log(obj);    // { '0': 'a', '1': 'b', '2': 'c', length: 3 }
console.log(obj[2]); // c


如果我想转换{ name: a, div :b, salary:c}
为该怎么办

2

更多的浏览器支持更灵活的方式是使用正常循环,例如:

const arr = ['a', 'b', 'c'],
obj = {};

for (let i=0; i<arr.length; i++) {
   obj[i] = arr[i];
}

但是,现代方式也可以使用传播运算符,例如:

{...arr}

对象分配

Object.assign({}, ['a', 'b', 'c']);

两者都将返回

{0: "a", 1: "b", 2: "c"}

1

您可以使用如下功能:

var toObject = function(array) {
    var o = {};
    for (var property in array) {
        if (String(property >>> 0) == property && property >>> 0 != 0xffffffff) {
            o[i] = array[i];
        }
    }
    return o;
};

这应该更有效地处理稀疏数组。


1

这是咖啡脚本中的解决方案

arrayToObj = (arr) ->
  obj = {}
  for v,i in arr
    obj[i] = v if v?
  obj

7
什么是咖啡脚本?我们在谈论JS!:D
m93a

2
这是一种可编译为JavaScript的语言:)
大卫(David)

6
Hmph,它使用奇怪的符号。我更喜欢普通的JS。
m93a

2
@David您可以在1行上执行整个for循环,以使整个事情仅3行。:)实施例obj[i] = v for v,i in arr when v?
XåpplI'-I0llwlg'I -
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.