Convert Array to Object
Solution 1
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" }
Solution 2
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.
Solution 3
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.
Solution 4
If you're using jquery:
$.extend({}, ['a', 'b', 'c']);
Solution 5
For completeness, ECMAScript 2015(ES6) spreading. Will require either a transpiler(Babel) or an environment running at least ES6.
console.log(
{ ...['a', 'b', 'c'] }
)
Comments
-
David Hellsing almost 2 years
What is the best way to convert:
['a','b','c']
to:
{ 0: 'a', 1: 'b', 2: 'c' }
-
Phrogz over 13 yearsI think you forgot to test that; it produces
{0:"c", 1:"b", 2:"a"}
. You either wantunshift
instead ofpop
or (better) start withi=arr.length-1
and decrement instead. -
Mic over 13 yearsyeah.. just changed it, but then it become less interesting :/
-
Dave Dopson about 12 yearsNote that your "typeOf" function is notoriously dangerous - some objects just happen to have a "length" property. I'd recommend using the methods in underscore.js, like "_.isArray(obj)".
-
Dave Dopson almost 12 yearsyou downvote my response, but no comment? My answer is correct and tested. What is the objection?
-
TrySpace almost 12 yearsWeird, 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...
-
Johan almost 12 yearsjust check for obj instanceof Array instead of checking for length
-
James Daly over 11 yearsthought this was great just added a few things for my own enjoyment returns an object you can't reference outside function so just showed example of that and adding something to the object property names
x = ['a','b','c'] var b = {} function toObject(arr) { var rv = {}; for (var i = 0; i < arr.length; ++i) if (arr[i] !== undefined) { rv['key_' + i] = arr[i]; } b = rv return b; } toObject(x) b.key_0
-
David Hellsing over 11 yearsThere are a couple of problems with this approach, 1; you are extending the native prototype. 2; you are using
for in
in an array wich will also loop through static properties of the array. 3; why are you excluding functions? -
David Hellsing over 11 yearsThis question has no underscore tag, and you are also assuming node.js or a require library.
-
Dave Dopson over 11 yearsunderscore 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
-
David Hellsing over 11 yearsStill, 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. -
Dave Dopson over 11 yearsYour suggestion to use _.extend is a good one. I didn't realize that would work on an array. Normally I prefer 'map' to 'each' because perf micro-optimization aside, 'map' can accomplish everything that 'each' accomplishes, reducing by 1 the number of methods I need to think about.... that's one of my few complaints about underscore, having too many methods where a smaller canonical set would suffice. JS1.6 seems to agree with me, defining a built in 'map', but no 'each' method.
-
Conner Ruhl over 11 yearsWhy are you using comma notation?
-
Aaron Miler about 11 yearsUsing underscore and Backbone and this solved my problem perfectly. Thanks.
-
m93a about 11 yearsWhat about
var arr = []; arr['foo'] = "bar"
? Can this be converted to object? -
Pointy about 11 years@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. -
m93a about 11 years@Pointy Nope, it's not an usual object - try converting to JSON, it treats really werid.
-
m93a about 11 yearsWhat's coffeescript? We are talking about JS! :D
-
Pointy about 11 years@m93a All array instances are objects. Properties with string (non-numeric) names like "foo" are merely properties of that object, and as such they're just like properties of any other object. The properties with numeric names (like "12" or "1002") are special in that the runtime system automatically adjusts the "length" property accordingly when values are assigned. Also,
.push()
,.pop()
,.slice()
, etc. all only work on numeric properties, and not properties like "foo". -
David about 11 yearsIt's a little language that compiles into JavaScript :)
-
m93a about 11 yearsHmph, it uses strange notation. I like plain JS more.
-
m93a about 11 years@Pointy Try to run this in your JS console:
var a = ["x", "y"]; a["foo"] = "z"; b = {1:"x",2:"y","foo":"z"}; console.log(JSON.stringify(a)); console.log(JSON.stringify(b));
. -
Pointy about 11 years@m93a the
JSON.stringify
code can tell the difference between a real Array instance and an object with numeric keys. When it sees a real array, all that it serializes is the "real" list of properties that comprise the numerically-indexed array. I have never noticed that behavior, but it's yet another good reason not to use an Array when you really just want an Object. -
BingeBoy almost 11 yearsPersonal preference to have the comma leading on the next line. I find this notation easier to read.
-
ivkremer over 10 years@Max I think there is no such behavior. The returned object is
{0: 'a', 1: 'b', 2: 'c'}
what is an expected result. -
Brett Zamir over 10 yearsThis 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.
-
Mark Giblin over 10 yearsNo it doesn't, the routine makes copies, the original is not touched.
-
Brett Zamir over 10 yearsYes, the original is touched. See jsfiddle.net/bRTv7 . The array lengths end up both being 0.
-
Mark Giblin over 10 yearsOk, the edited version I just changed it with does not destroy the arrays, find that strange that it should have done that.
-
Brett Zamir over 10 years
var tmp = this;
had just made a reference, not a copy, as with the keys array you had passed into the function. As mentioned, JavaScript works differently than PHP. I also fixed your current function's while loop condition to be>=0
instead of>0
because otherwise you would avoid including the first item in the array (at the 0 index). -
Brett Zamir over 10 yearsSee jsfiddle.net/WpM3h for your latest version before my modification: jsfiddle.net/WpM3h
-
2540625 over 9 years@Pointy, what are your one- and two-letter variables supposed to indicate?
-
Pointy over 9 years@janaspage well "i" is just a numeric index into the numbered properties of the array, and "rv" is the return value of that function.
-
Davi Lima over 9 yearsIs there a way to use $.extend while also informing the keys in a non-numerical manner, ie: making calcultations on the array items?
-
Charlie Martin over 9 yearsThe "you must answer without mentioning underscore or lo-dash" people are so annoying. Comparable to saying that you must answer C++ questions without mentioning the standard libraries. If underscore or lo-dash is not an option, the OP should mention that.
-
XåpplI'-I0llwlg'I - about 9 years@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?
-
Qix - MONICA WAS MISTREATED over 8 yearsCould even do
l = arr.length
, and thenwhile (l && (obj[--l] = arr.pop())){}
(I realize this is old, but why not simplify it even further). -
Mic over 8 years@Qix, Nice shortening
-
Oriol about 8 years(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 thinkObject.assign
is much better. -
Oriol about 8 yearsThe loop will stop if the array contains a falsy value. You should check
i < a.length
instead ofa[i]
. -
Benjamin Gruenbaum almost 8 years@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.
-
huygn over 7 yearscleaner way to avoid param reassign
const obj = arr.reduce((obj, cur, i) => { return { ...obj, [i]: cur }; }, {});
-
Hanmaslah over 7 yearsWorks really well. Thanks
-
morewry about 7 years@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.
-
Charlie Martin about 7 years@morewry I was trying to suggest that they should be in the standard libraries in javascript. Not that they are.
_.extend
was added to the standard libraries in ECMA 6 asObject.assign
anyway -
Shannon Hochkins about 7 yearsNot 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']]);
-
Wanjia almost 7 yearsThis 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. -
Watchmaker over 6 yearsIf you had an array of objects and you would like to transform that array in a n object you could do:
const optionPriceArray = [ {option: 'economy', price:200}, {option: 'tourist', price:100} ];
and then:const newObj = optionPriceArray.reduce(function(acc, cur) { acc[cur.option] = cur.price; return acc; }, {});
which outputs://newObj = {'economy': 200, 'tourist': 100}
-
VivekN about 6 years@huygn will your approach be not more expensive in terms of number of lines that it has to process.Since everytime instead of using the same object, you are creating a new one by spreading the params which to es5 would be a for loop iterating over the properties.It seems that this might just make the function slow.What do you think?
-
Aluan Haddad about 6 yearsActually this isn't natively available in ES2015 either. It is very elegant however.
-
Marc Scheib about 6 yearsArrow + destructuring syntax w/o explicit return:
const obj = arr.reduce((obj, cur, i) => ({ ...obj, [i]: cur }), {});
-
miro almost 6 yearsAs @VivekN said, is it necessary to create new object every time? What about
arr.reduce((obj, cur, i) => (obj[i]=cur,obj), {});
? -
Pointy almost 6 years@eugene_sunic indeed, but that approach was not available when I answered this in 2010 :)
-
Brett Zamir over 5 yearsThis 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)...
-
Brett Zamir over 5 yearsBut hmm,
Array.isArray
is returningtrue
for the "object" here even thoughinstanceof Array
does not... -
Benjamin Gruenbaum over 5 years@BrettZamir that sounds like a bug :D
-
Prashant Pimpale over 5 yearsWhat if I want to convert to
{ name: a, div :b, salary:c}
-
Dan Dascalescu about 5 yearsWhat did you intend with
[/docs]
? It would be more useful to make the code snippets executable. -
dhruvpatel almost 5 yearsHelpful with maintaining a redux store when you are using a map of objects and you need to drop one of the keys
-
HappyHands31 almost 5 yearsJust 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]}
-
Jeff Fairley over 4 yearsAlso,
Object.fromEntries(Object.entries(nodes).map(([key, value] => [key, value.interfaces]))
-
romellem over 4 yearsAs @miro points out, creating a new object every time is not necessary, and in fact much slower than manipulating the initial object that was created. Running a JSPerf test on an array of 1000 elements, creating a new object every time is 1,000 times slower than mutating the existing object. jsperf.com/…
-
Mark Giblin over 4 yearsUpdated method that should be supported in older browsers as JSON has been around longer than ECMA added new code features
-
Mike K about 4 yearsThis is what I was looking for. I didn't need the indeces, I needed to transform the array into retained key-value pairs.
-
Faisal Mehmood Awan about 4 yearssuper awsome and short test
-
Menai Ala Eddine - Aladdin about 4 yearsOriol, is there a way to set a fixed key instead of 0 & 1?
-
its4zahoor almost 4 yearsthe returns an array of objects. the question was about a single object with index as a key and value as the value.
-
Thomas Beauvais over 3 yearsThis 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.
-
PEZO about 3 yearsIs it faster then the other solutions?
-
Admin about 3 yearswhy mvc does not allow to us to post array. Why we must convert array to object?
-
Kanish about 3 yearshow to get result - { "a": "a", "b":"b", "c":"c" } using spread?
-
panzerpower about 3 years
-
Gel almost 3 yearswhat if i want the key not as 0,1,2 but the same as the value? like: {a: 'a'} How do we do that ?
-
David Hellsing over 2 years@Gel Use
reduce
like:arr.reduce((a, v) => ({ ...a, [v]: v}), {})
-
Balazs Zsoldos over 2 yearsI am wondering how fast this reduce thing is. In each iteration the object is cloned again and again with spread operator?
-
Lasf about 2 yearsThis is nice and easily modified to meet other reqs
-
alextrastero almost 2 yearsThis is just what I was looking for, I can do:
{...arr}
and done -
Cristik almost 2 yearsThis is the same solution as provided in the top answer
-
Cristik almost 2 yearsThe same solution was already provided in the second top answer.
-
Cristik almost 2 yearsThe same solution was already provided in the second top answer.
-
Meitham almost 2 years@Cristik it does now, but it didn’t at the time. It’s one annoying trend now for top answers to copy snippets from bottom answers without providing credit.
-
Cristik almost 2 yearsI looked at the revision history before posting the comment, and it showed the edit that introduced the
reduce()
was added on Mar 12, 2014, which was before your answer was posted.