DEV Community

Cover image for How to convert an array into an object in javascript
Aaron
Aaron

Posted on • Originally published at afewminutesofcode.com

Javascript Array to Object How to convert an array into an object in javascript

image from undraw.co

Originally posted on afewminutesofcode.com

To convert an array into an object we will create a function and give it 2 properties, an array and a key.

const convertArrayToObject = (array, key) => {};
Enter fullscreen mode Exit fullscreen mode

We will then reduce the array, and create a unique property for each item based on the key we have passed in.

We also need to remember to set an initial Value, and also pass in the current value (...obj in the below).

const convertArrayToObject = (array, key) => {
  const initialValue = {};
  return array.reduce((obj, item) => {
    return {
      ...obj,
      [item[key]]: item,
    };
  }, initialValue);
};
Enter fullscreen mode Exit fullscreen mode

So now if we log out our function (passing in the array and our key which is a unique identifier in this case the id property) we will see our array is now an object.

console.log(
  convertArrayToObject(
    [
      { id: 111, name: 'John', age: 29 },
      { id: 112, name: 'Sarah', age: 25 },
      { id: 122, name: 'Kate', age: 22 },
      { id: 123, name: 'Tom', age: 21 },
      { id: 125, name: 'Emma', age: 24 },
    ],
    'id',
  ),
);
Enter fullscreen mode Exit fullscreen mode

returns

{
  111:{ id: 111, name: 'John', age: 29 },
  112:{ id: 112, name: 'Sarah', age: 25 },
  122:{ id: 122, name: 'Kate', age: 22 },
  123:{ id: 123, name: 'Tom', age: 21 },
  125:{ id: 125, name: 'Emma', age: 24 }
}
Enter fullscreen mode Exit fullscreen mode

We can now easily look up data in our array by an id and use it as required.

If you are looking for some more tips or want to be notified when my next post is available follow Me Online Here:

Instagram
Facebook
afewminutesofcode.com
Twitter
Pinterest

Discussion (31)

Collapse
mdor profile image
Marco Antonio Dominguez • Edited on

This is good, anyhow is an antipattern, it should be something like:

const convertArrayToObject = (array, key) => 
  array.reduce((acc, curr) => {
    acc[curr[key]] = curr;
    return acc;
  }, {});

// Even concise
const convertArrayToObject = (array, key) => 
  array.reduce((acc, curr) =>(acc[curr[key]] = curr, acc), {});
// Basically everything inside parentheses will be evaluated, only the last value used will be only returned.

Enter fullscreen mode Exit fullscreen mode

In this way, you avoid the spread op which is a way expensive than a single assignment

Collapse
vhoyer profile image
Vinícius Hoyer

Hey, man, I like code golfing too, but just because something can be written more concisely, it doesn't mean we should. Your second solution is kinda difficult to read because it's so cluttered and it also obligates people to know what the comma operator is and how it works. I just don't see how this is better than your first solution once the bundler will already minify the code for us, we don't need to write and read minified code, just be aware everyone, if you're gonna copy this, copy the first one, the people reading your code in the future will be happier :D

Collapse
afewminutesofcode profile image
Aaron Author

Thanks for taking the time to help me and others out here! I am going to read up on the Comma operator in JavaScript developer.mozilla.org/en-US/docs/W... do you have any other resources you recomend here?

Collapse
ansaganio profile image
Ansagan Islamgali

There is no comma operator here

Thread Thread
vhoyer profile image
Vinícius Hoyer

yes, there is, it's right above the line of the "Basically everything..."

Collapse
frankdspeed profile image
Frank Lemanschik

there is no item var around it should be curr did you even write that code alone?

Collapse
bradtaniguchi profile image
Brad • Edited on

Nice!

I had to write one of these the other day.

Here's a slightly more concise version, where you throw out extra brackets and use an implicit return 😄 :

const convertArrayToObject = (array, key) =>
  array.reduce(
    (obj, item) => ({
      ...obj,
      [item[key]]: item
    }),
    {}
  );
Enter fullscreen mode Exit fullscreen mode

the [item[key]] tripped me up initially haha.

Collapse
afewminutesofcode profile image
Aaron Author

Thanks so much for pointing this out Brad! I have used this syntax for one liner map functions but had overlooked using it with reduce before. I am going to make sure I use it in the future, to keep my code more concise.

Collapse
nutritsio profile image
Serega

Thanks man💪

Collapse
paritho profile image
Paul Thompson

So long as you don't have to support older browsers, or are using Babel, new ES features do this without the need of a helper function. See the MDN docs for Object.fromEntires.

Collapse
afewminutesofcode profile image
Aaron Author

Thanks Paul, I have done some reading on this feature a few months back but hadn't seen how I could apply this to my problem.

There is another comment from ygorbunkov which demonstrates how to do this so I will have a reference point if I need to use something similar again soon!

Collapse
nicolege profile image
nicole-ge

I have another example to wotk with your Code, but I didn't reach it.

My Array:

[
{"name":"Product 1","series":{"name":"Area 1","value":3}},
{"name":"Product 2","series":{"name":"Area 2","value":3}},
{"name":"Product 1","series":{"name":"Area 2","value":1}},
]

Need to convert it to an object like this:

[ {"name": "Product 1",
"series":[{"name":"Area 1","value":3},{"name":"Area 2","value":1}] },
{"name":"Product 2",
"series":[{"name":"Area 2","value":3}] }
];

It would be nice if you could give my any advice how to reach this by adopting your Code?

Collapse
fetishlace profile image
fetishlace

I would do something like this below to get the result (not nice or fast but should do the job :D):

const arr = [
{"name":"Product 1","series":{"name":"Area 1","value":3}},
{"name":"Product 2","series":{"name":"Area 2","value":3}},
{"name":"Product 1","series":{"name":"Area 2","value":1}},
];

const result = [... new Set(arr.map(x=>x.name))].map(x=>({"name":x,"series":[]}));

arr.forEach(x=>result.find(y=>y.name===x.name).series.push(x.series));

JSON.stringify(result,null,3);

Collapse
nicolege profile image
nicole-ge

Thank you this works very good.

I have one question:
what does arr.forEach(x=>result.find(y=>y.name===x.name).series.push(x.series));

I don't understand this function. I left it out and works. What does it?

Thread Thread
fetishlace profile image
fetishlace • Edited on

It cannot work without it, it makes no sense. I've just generated array with unique names and empty series array at first (result), this one is pushing all the series objects data into these empty series arrays in result array.

It's just going through original array (arr) to pick series object and push it in result series array - names properties has to match hence y.name===x.name

Thread Thread
nicolege profile image
nicole-ge

to understand the code a bit better, how I have to adjust it to get the following result:

[
{"name":"Area 1","value":3},
{"name":"Area 2","value":3},
{"name":"Area 2","value":1}
];

Thread Thread
fetishlace profile image
fetishlace

From that?
let arr = [
{"name":"Product 1","series":{"name":"Area 1","value":3}},
{"name":"Product 2","series":{"name":"Area 2","value":3}},
{"name":"Product 1","series":{"name":"Area 2","value":1}},
]
U can just remap it
arr.map(x=>x.series)

Collapse
artezan profile image
artezan • Edited on

I faced out with this problem and I took as a reference: stackoverflow.com/a/44325124

And I created some similar that your solution but with less lines and more faster

const convertArrayToObject = (array, key) => 
   array.reduce((obj, item) => ((obj[[item[key]]] = item), obj), {});



Enter fullscreen mode Exit fullscreen mode
Collapse
afewminutesofcode profile image
Aaron Author

Thanks for the reference their artezan, the explanations in those answers have really helped my understanding!

Collapse
vhoyer profile image
Vinícius Hoyer • Edited on

I know that this post is from 2019, but I guess I will offer some more recent way of writing this:

const convert = (array, keyName) => Object.fromEntries(
  array.map(item => [item[keyName], item])
);
Enter fullscreen mode Exit fullscreen mode

Or if you want to remove the key from the object:

const convert = (array, keyName) => Object.fromEntries(
  array.map(({ [keyName]: key, ...item }) => [key, item])
);
Enter fullscreen mode Exit fullscreen mode
Collapse
kukuster profile image
Kukuster • Edited on

Here's type-friendly version in TypeScript

export function convertArrayToObject
<
T extends { [prop in string | number]: any },
K extends keyof Pick<T, {
    [Key in keyof T]: T[Key] extends string | number ? Key : never
}[keyof T]> = keyof Pick<T, {
    [Key in keyof T]: T[Key] extends string | number ? Key : never
}[keyof T]>,
A extends T[] = T[]
>
(array: readonly T[], key: K)
{
    const initialValue = {};
    return array.reduce((obj, item) => {
        return {
            ...obj,
            [item[key]]: item,
        };
    }, initialValue) as { [propkey in A[number][K]]: A[number]; };
}
Enter fullscreen mode Exit fullscreen mode

Notes:
• TypeScript 4.0+ (tested on 4.0.x and 4.1.x)

• for the 2nd arg TS will allow and suggest only those keys for which all objects hold a value of type number or string (only those types by which any object props can be indexed).
So if all those objects had a prop BD with a string value for all the people, except John's BD was a Date object, TS won't suggest nor allow you to choose 'BD' for the 2nd arg.

• that single usage of any here is intentional. As a result, it's going to be collapsed, whereas using unknown would require several additional checks.

• usage of as operator to assert the type of return value is intentional. May be unnecessary in future TypeScript versions.

• works perfectly for variable data, but only almost perfect for constant data.
Here in this example if you denote that test array as const, TS will be able to tell you that the object has 5 properties 111, 112, 122, 123, 125, but won't be able to tell you which object exactly under each key and think its a union type of all objects for each key.
So, given the passed array had as const annotation and the returned object from the example is called fooobj:

const bar = fooobj[111];
// it thinks bar is of type of one of the objects from the original array

const name = bar.name;
// TS suggests name is of type 'John' | 'Sarah' | 'Kate' | 'Tom' | 'Emma'

if (bar.id === 111){
    // only here types collapse, asserting the exact value for bar props
    const name = bar.name;
    // TS is convinced that name === 'John'
}

Enter fullscreen mode Exit fullscreen mode
Collapse
__abshir profile image
{ abshir }

Thank you, this was very handy.
I remixed it a little:

const convertArrayToObject = (array) => {
    return _.reduce(array, (accumulator, currentValue) => {
        accumulator = Object.assign(accumulator, currentValue);
        return accumulator;
    }, {});
};
Enter fullscreen mode Exit fullscreen mode
Collapse
__abshir profile image
{ abshir }

I should have mentioned that I've used the lodash reduce method here instead of the javascript reduce

Collapse
ygorbunkov profile image
ygorbunkov

What about Object.fromEntries()?

const convertArrayToObject = (arr,propName) => Object.fromEntries(arr.map(({[propName]:prop,...rest}) => [prop, {...rest}]));

Collapse
afewminutesofcode profile image
Aaron Author

Thanks so much ygorbunkov, I have done some reading on this feature a few months back but hadn't seen how I could apply this to my problem, I will have a reference point if I need to use something similar again soon!

Collapse
ygorbunkov profile image
ygorbunkov

You shall bear in mind, though, it still works noticeably slower than reduce(). Hope, it will get optimised as this feature becomes more 'mainstream'.

Thread Thread
afewminutesofcode profile image
Aaron Author

Thank you, I will keep this in mind. Have a great day

Collapse
rahulsachdeva02 profile image
rahulsachdeva02

Nice !

how to convert something having more than one value of id like below :
for this example i understand there wont be more than one id but in my case there will be same value.

[
  { id: 111, name: 'John', age: 29 },
  { id: 111, name: 'Rob', age: 29 },
  { id: 111, name: 'Joe', age: 29 },
  { id: 112, name: 'Sarah', age: 25 },
  { id: 122, name: 'Kate', age: 22 },
  { id: 123, name: 'Tom', age: 21 },
  { id: 125, name: 'Emma', age: 24 },
],
Enter fullscreen mode Exit fullscreen mode

to

{
111:[{ id: 111, name: 'John', age: 29 },{ id: 111, name: 'Rob', age: 29 },{ id: 111, name: 'Joe', age: 29 }]
112:{ id: 112, name: 'Sarah', age: 25 },
122:{ id: 122, name: 'Kate', age: 22 },
123:{ id: 123, name: 'Tom', age: 21 },
125:{ id: 125, name: 'Emma', age: 24 }
}

Collapse
iggredible profile image
Igor Irianto

One Vuejs style guide recommends to normalize array into object. This will come in super handy!! Thanks!

Collapse
afewminutesofcode profile image
Aaron Author

Good to hear! Also check out the comments as some awesome developers have taken the time to suggest some small improvements as well!

Collapse
vijayasanthamdev profile image
vijayasantham-dev • Edited on

Thanks man. this really helpful for me