ChatGPT解决这个技术问题 Extra ChatGPT

Convert Array to Object

What is the best way to convert:

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

to:

{
  0: 'a',
  1: 'b',
  2: 'c'
}
Its worth pointing out that Javascript arrays are objects.
If anyone else is looking for a Lodash solution, consider _.keyBy (formerly _.indexBy): lodash.com/docs#keyBy
This is a bit confusing because arrays are objects already, but I guess the point of the question is converting the array exotic object to an ordinary object.
A simple way to do this with Lodash is _.toPlainObject. Ex: var myObj = _.toPlainObject(myArr)

D
David Hellsing

ECMAScript 6 introduces the easily polyfillable Object.assign:

The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

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

The own length property of the array is not copied because it isn't enumerable.

Also, you can use ES8 spread syntax on objects to achieve the same result:

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

For custom keys you can use reduce:

['a', 'b', 'c'].reduce((a, v) => ({ ...a, [v]: v}), {}) 
// { a: "a", b: "b", c: "c" }

Just want to point out - if you already have an array of sorted properties from the original object, using the spread operator is what will turn that array directly into a new object: { ...[sortedArray]}
Oriol, is there a way to set a fixed key instead of 0 & 1?
This is usually not what you want. Usually you want to use a property in the array element as a key. Thus, the reduce is what you want.
what if i want the key not as 0,1,2 but the same as the value? like: {a: 'a'} How do we do that ?
@Gel Use reduce like: arr.reduce((a, v) => ({ ...a, [v]: v}), {})
J
Jordan Frankfurt

With a function like this:

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

Your array already is more-or-less just an object, but arrays do have some "interesting" and special behavior with respect to integer-named properties. The above will give you a plain object.

edit oh also you might want to account for "holes" in the array:

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

In modern JavaScript runtimes, you can use the .reduce() method:

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

That one also avoids "holes" in the array, because that's how .reduce() works.


@m93a it already is an object. In JavaScript, there's really no point creating an Array instance ([]) if you're not going to use numeric property keys and the "length" property.
cleaner way to avoid param reassign const obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
Arrow + destructuring syntax w/o explicit return: const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
As @VivekN said, is it necessary to create new object every time? What about arr.reduce((obj, cur, i) => (obj[i]=cur,obj), {}); ?
@eugene_sunic indeed, but that approach was not available when I answered this in 2010 :)
r
roland

You could use an accumulator 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"

Pass an empty object {} as a starting point; then "augment" that object incrementally. At the end of the iterations, result will be {"0": "a", "1": "b", "2": "c"}

If your array is a set of key-value pair objects:

[{ 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;
}, {});

will produce: {a: 1, b: 2, c: 3}

For the sake of completeness, reduceRight allows you to iterate over your array in reverse order:

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

will produce: {c:3, b:2, a:1}

Your accumulator can be of any type for you specific purpose. For example in order to swap the key and value of your object in an array, pass []:

[{ 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

will produce: [{1: "a"}, {2: "b"}, {3: "c"}]

Unlike map, reduce may not be used as a 1-1 mapping. You have full control over the items you want to include or exclude. Therefore reduce allows you to achieve what filter does, which makes reduce very versatile:

[{ 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

will produce: [{2: "b"}, {3: "c"}]

Caution: reduce and Object.key are part of ECMA 5th edition; you should provide a polyfill for browsers that don't support them (notably IE8).

See a default implementation by Mozilla.


Helpful with maintaining a redux store when you are using a map of objects and you need to drop one of the keys
M
Max

If you're using jquery:

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

Weird, if I give in an Array variable it puts every character in a separate object: 0: "a", 1: ",", 2: "b"... So it ignores the quotes, but includes the commas...
@Max I think there is no such behavior. The returned object is {0: 'a', 1: 'b', 2: 'c'} what is an expected result.
Is there a way to use $.extend while also informing the keys in a non-numerical manner, ie: making calcultations on the array items?
super awsome and short test
v
vsync

For completeness, ECMAScript 2015(ES6) spreading. Will require either a transpiler(Babel) or an environment running at least ES6.

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


Actually this isn't natively available in ES2015 either. It is very elegant however.
how to get result - { "a": "a", "b":"b", "c":"c" } using spread?
P
Prerna Jain

I'd probably write it this way (since very rarely I'll not be having the underscorejs library at hand):

var _ = require('underscore');

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

you downvote my response, but no comment? My answer is correct and tested. What is the objection?
This question has no underscore tag, and you are also assuming node.js or a require library.
underscore is pretty common on both client and server. It's assumed for Backbone.js and is probably THE most common utility library. That being said, I included the require line to make it clear I was using a library. There's no 1-liner for describing "add underscore.js to your page", so some translation is required for a browser environment
Still, if you’re using undserscore, a simple obj=_.extend({},a); would do the job. Also, if you are iterating through arrays I’d say _.each would be more appropriate than _.map. All in all, this is not a good answer on several levels.
@CharlieMartin that analogy is completely flawed, because lodash, underscore, and jQuery are not "standard libraries" and, in a great number of JavaScript use cases, adding libraries directly impacts end users, which one should not do for trivial reasons.
J
Johnathan Kanarek

In case you want to use one of the properties of the iterated objects as key, for example:

// from:
const arr = [
    {
        sid: 123,
        name: 'aaa'
    },
    {
        sid: 456,
        name: 'bbb'
    },
    {
        sid: 789,
        name: 'ccc'
    }
];
// to:
{
  '123': { sid: 123, name: 'aaa' },
  '456': { sid: 456, name: 'bbb' },
  '789': { sid: 789, name: 'ccc' }
}

Use:

const result = arr.reduce((obj, cur) => ({...obj, [cur.sid]: cur}), {})

I am wondering how fast this reduce thing is. In each iteration the object is cloned again and again with spread operator?
K
KARTHIKEYAN.A

we can use Object.assign and array.reduce function to convert an Array to Object.

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


This is what I was looking for. I didn't need the indeces, I needed to transform the array into retained key-value pairs.
plus one for the KungFu, I need it for conversion of arr = [{ b: 1, d: 2 }] to obj.
B
Benjamin Gruenbaum

Here is an O(1) ES2015 method just for completeness.

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) According to MDN, changing the [[Prototype]] of an object is a very slow operation. (2) This does not remove the own length property. (3) The object is still an array, Array.isArray(arr) === true. (4) Special array behaviors are not removed, e.g. arr.length = 0 removes all indices. (5) Therefore, I think Object.assign is much better.
@Oriol mdn is wrong, at least in V8 (but also other engines) this is a pretty fast operation in this particular case - since objects have a numerical store anyway this is basically changing two pointers.
This also can be used for the fact that it is apparently unique among the other quick solutions, of preserving any non-index ("own") properties on the array (i.e., non-positive-integer properties)...
But hmm, Array.isArray is returning true for the "object" here even though instanceof Array does not...
@BrettZamir that sounds like a bug :D
B
Brett Zamir

FWIW, one another recent approach is to use the new Object.fromEntries along with Object.entries as follows:

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

...which allows for avoiding storing sparse array items as undefined or null and preserves non-index (e.g., non-positive-integer/non-numeric) keys.

{ 0: "a", 1: "b", 2: "c", "-2": "d", hello: "e" }

(Same result here as with @Paul Draper's Object.assign answer.)

One may wish to add arr.length, however, as that is not included:

obj.length = arr.length;

you can use arr.entries() instead of Object.entries(arr)
R
RIYAJ KHAN

Using javascript#forEach one can do this

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

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

With ECMA6:

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

m
murthy naika k

If you're using ES6, you can use Object.assign and the spread operator

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

If you have nested array like

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

Not only are your variable names different, but your example will not work, creating a map from the constructor initially requires 2d key-value Array. new Map([['key1', 'value1'], ['key2', 'value2']]);
M
Mic

A quick and dirty one:

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

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

I think you forgot to test that; it produces {0:"c", 1:"b", 2:"a"}. You either want unshift instead of pop or (better) start with i=arr.length-1 and decrement instead.
yeah.. just changed it, but then it become less interesting :/
Could even do l = arr.length, and then while (l && (obj[--l] = arr.pop())){} (I realize this is old, but why not simplify it even further).
@Qix, Nice shortening
Is it faster then the other solutions?
l
lordkrandel

Quick and dirty #2:

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

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

Why are you using comma notation?
Personal preference to have the comma leading on the next line. I find this notation easier to read.
The loop will stop if the array contains a falsy value. You should check i < a.length instead of a[i].
A
Alireza

More browser supported and more flexible way of doing that is using a normal loop, something like:

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

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

But also the modern way could be using the spread operator, like:

{...arr}

Or Object assign:

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

Both will return:

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

M
Mark Giblin

A simple and cheeky method of quickly converting an Array of items in to an Object

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

Then using it like so...

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

Output:

pork pie

Checking the type:

typeof obj
"object"

AND things wouldn't be complete if there wasn't a prototype method

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

Using like:

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

Output:

cheese whizz

*NOTE that there is no naming routine, so if you want to have specific names, then you will need to continue using the existing methods below.

Older method

This allows you to generate from an array an object with keys you define in the order you want them.

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); will output "paint", the function has to have arrays of equal length or you get an empty object.

Here is an updated method

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

This destroys both the keys array content and, despite the internal comment, also the values array (its contents). JavaScript works differently than PHP with JavaScript automatically acting by reference on the properties of an object/array.
No it doesn't, the routine makes copies, the original is not touched.
Yes, the original is touched. See jsfiddle.net/bRTv7 . The array lengths end up both being 0.
Ok, the edited version I just changed it with does not destroy the arrays, find that strange that it should have done that.
Updated method that should be supported in older browsers as JSON has been around longer than ECMA added new code features
t
test30
.reduce((o,v,i)=>(o[i]=v,o), {})

[docs]

or more verbose

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

or

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

shortest one with vanilla JS

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

some more complex example

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

even shorter (by using 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]


What did you intend with [/docs]? It would be more useful to make the code snippets executable.
a
acontell

As of Lodash 3.0.0 you can use _.toPlainObject

var obj = _.toPlainObject(['a', 'b', 'c']); console.log(obj);


S
Shannon Hochkins

If you can use Map or Object.assign, it's very easy.

Create an array:

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

The below creates an object with index as keys:

Object.assign({}, languages)

Replicate the same as above with Maps

Converts to an index based object {0 : 'css'} etc...

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

Convert to an value based object {css : 'css is great'} etc...

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

i
isherwood

If someone is searching for a Typescript method, i wrote this:

const arrayToObject = <T extends Record<K, any>, K extends keyof any>(
  array: T[] = [],
  getKey: (item: T) => K,
) =>
  array.reduce((obj, cur) => {
    const key = getKey(cur)
    return ({...obj, [key]: cur})
  }, {} as Record<K, T>)

It will:

enforce first param to be array of objects help to select the key enforce the key to be an key of all array items

Example:

// from:
const array = [
    { sid: 123, name: 'aaa', extra: 1 },
    { sid: 456, name: 'bbb' },
    { sid: 789, name: 'ccc' }
];
// to:
{
  '123': { sid: 123, name: 'aaa' },
  '456': { sid: 456, name: 'bbb' },
  '789': { sid: 789, name: 'ccc' }
}

usage:

const obj = arrayToObject(array, item => item.sid) // ok
const obj = arrayToObject(array, item => item.extra) // error

Here's a demo.


This is nice and easily modified to meet other reqs
Excellent little solution, works like a charm! How to change the output into '123': 'aaa' as per your example?
Modified function for anyone looking to do what I needed: const arrayToObject = <T extends Record<K, any>, K extends keyof any>( array: T[] = [], getKey: (item: T) => K, ) => array.reduce((obj, cur) => { const key = getKey(cur) return ({...obj, [key]: Object.entries(cur).reduce((str, [p, val]) => { return ${val}; }, '') }) }, {} as Record<K, T>);
J
JVE999

Here's a recursive function I just wrote. It's simple and works well.

// 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;
}

Here's an example (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));

https://i.stack.imgur.com/KZHoT.png


Works really well. Thanks
This should be higher up, if you have ['a' = '1', 'b' = '2', 'c' = '3'] and want it like {a: 1, b: 2, c: 3} this works perfect.
C
Community

I would do this simply with Array.of(). Array of has the ability to use it's context as a constructor.

NOTE 2 The of function is an intentionally generic factory method; it does not require that its this value be the Array constructor. Therefore it can be transferred to or inherited by other constructors that may be called with a single numeric argument.

So we may bind Array.of() to a function and generate an array like object.

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

By utilizing Array.of() one can even do array sub-classing.


M
Mahdi Bashirpour

let i = 0; let myArray = ["first", "second", "third", "fourth"]; const arrayToObject = (arr) => Object.assign({}, ...arr.map(item => ({[i++]: item}))); console.log(arrayToObject(myArray));

Or use

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


S
SridharKritha

ES5 - Solution:

Using Array prototype function 'push' and 'apply' you can populate the object with the array elements.

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


What if I want to convert to { name: a, div :b, salary:c}
B
Bhangun Hartani

Try using reflect to copy from array item to object.

var arr =['aa:23','bb:44','cc:55']
    var obj ={}
    arr.forEach(e => {
        var ee = e.split(':')
        Reflect.set(obj,ee[0],ee[1])
    });
    console.log(obj) // { aa: '23', bb: '44', cc: '55' }

P
Pablo Cabrera

You could use a function like this:

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

This one should handle sparse arrays more efficiently.


A
Adnan Y

It's not directly relevant but I came here searching for a one liner for merging nested objects such as

const nodes = {
    node1: {
        interfaces: {if1: {}, if2: {}}
    },
    node2: {
        interfaces: {if3: {}, if4: {}}
    },
    node3: {
        interfaces: {if5: {}, if6: {}}
    },
}

The solution is to use a combination of reduce and object spread:

const allInterfaces = nodes => Object.keys(nodes).reduce((res, key) => ({...res, ...nodes[key].interfaces}), {})

Also, Object.fromEntries(Object.entries(nodes).map(([key, value] => [key, value.interfaces]))
D
Daniel Snell

Simplest way to do this is the following:

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

function ConvertArr(arr) { 
 if (typeof(arr) === 'array') {
 Object.assign(obj, arr);
}

This way it only runs if it is an array, however, you can run this with let global object variable or without, that's up to you, if you run without let, just do Object.assign({}, arr).


This is the same solution as provided in the top answer
a
ascripter

Use the javascript lodash library. There is a simple method _.mapKeys(object, [iteratee=_.identity]) that can do the conversion.


D
David

Here's a solution in coffeescript

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

What's coffeescript? We are talking about JS! :D
It's a little language that compiles into JavaScript :)
Hmph, it uses strange notation. I like plain JS more.
@David You could do the entire for loop on 1 line to make the whole thing only 3 lines. :) Example: obj[i] = v for v,i in arr when v?