DEV Community

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

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

afewminutesofcode profile image Aaron Originally published at afewminutesofcode.com ・2 min read

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

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

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',
  ),
);

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

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

pic
Editor guide
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
bradtaniguchi profile image
Brad

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

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
mdor profile image
Marco Antonio Dominguez

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[item[key]] = item, acc), {});
// Basically everything inside parentheses will be evaluated, only the last value used will be only returned.

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

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

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

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



Collapse
afewminutesofcode profile image
Aaron Author

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

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
kukuster profile image
Kukuster

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
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
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!