Rewriting JavaScript: Converting an Array of Objects to an Object.

TLDR; See banner image.

In my adventures to better understand Javascript I have come across many amazing (functional) solutions to everyday problems. But one has always stumped me to no end, well, until just recently that is. Converting an Array of Objects to an Object (in a good functional way!).

The Problem

First lets give a small snippet of code…

const peopleArray = [
{ id: 123, name: "dave", age: 23 },
{ id: 456, name: "chris", age: 23 },
{ id: 789, name: "bob", age: 23 },
{ id: 101, name: "tom", age: 23 },
{ id: 102, name: "tim", age: 23 }
]

The snippet is quite simple, an array of people objects where each object contains id, name, and age.

For this problem lets assume you have been given the peopleArray and an id of the user and need to select them from the peopleArray.

Below is a snippet of how you would normally select the user:

let idToSelect = 789
let selectedPerson
for (let person of peopleArray) {
if (person.id === idToSelect) {
selectedPerson = person;
break;
}
}

This is fairly simple and will traverse the array and assign the correct person to selectedPerson. This presents many problems though, mainly it introduces mutation into your code. Scary!

The Solution

For me the ideal solution would be to convert the array into an object that looks like the following:

const peopleObject = {
"123": { id: 123, name: "dave", age: 23 },
"456": { id: 456, name: "chris", age: 23 },
"789": { id: 789, name: "bob", age: 23 },
"101": { id: 101, name: "tom", age: 23 },
"102": { id: 102, name: "tim", age: 23 }
}

If our data is organized in this format you can simply select a person based on their id. Preventing the need to traverse an array!!

const idToSelect = "789";
const selectedPerson = peopleObject[idToSelect];

This is much cleaner, and removes mutation and complexity from our code base. But in many cases you may not be able to control the format that the data is presented to you. So it may be best to convert that data on the fly. Luckily ES6 provides us a way to make this conversion.

Note: If you have not learned about Array.reduce() now is the time to do so. One of my past articles has links to resources about using Array.reduce() as well as an example and simple explanation.
const arrayToObject = (array) =>
array.reduce((obj, item) => {
obj[item.id] = item
return obj
}, {})
const peopleObject = arrayToObject(peopleArray)
console.log(peopleObject[idToSelect])

What we do in the snippet above is use reduce, which returns accumulator (obj), to which we append each item in the array using that items id. This will convert our array of objects into an object of objects. YAY! (If reduce is confusing you please please please go check them out here! They are freakin amazing!)

The problem is that this snippet is limited to objects where the new object key is going to be id. Lets abstract this so the function is re-useable in all situations!

const arrayToObject = (array, keyField) =>
array.reduce((obj, item) => {
obj[item[keyField]] = item
return obj
}, {})
const peopleObject = arrayToObject(peopleArray, "id")
console.log(peopleObject[idToSelect])

The above code now accepts a keyField which allows us to use this function to convert any array of objects. Not just those who have an the field id. This is important for reusability of our code.

Conclusion

By converting our array of objects to an object of objects, in a functional way of course, we have limited the need for mutation in our codebase! If you want a bit more information on why it may be better to store your data in objects instead of arrays check out this article by Firebase.

Thanks!

Thanks for reading! I’ll be covering more topics in the near future about rewriting basic Javascript concepts using the new standards.

Useful Reading

Additions/Edits

As pointed out by @joaoeffting (thanks for pointing it out!) to perform the same operation on the original array in one line to find the selected user is super simple:

const selectedPerson = peopleArray.find(person => person.id === idToSelect)

This is a fantastic solution when you need to access the data in one off situations, or if you just prefer your data to stay in the array format.

Additionally Taq Karim pointed out a killer single line solution that eliminates the return statement and makes fantastic use of the spread operator. Absolutely great solution thats super exciting and really shows off Javascripts power and syntax! Thanks again Taq Karim!

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

Please leave a comment below with questions, concerns, or cake (bring cake if you're going to roast me)!