Selects logo a praymentis.

I AM SELECT

Nov 08
2017
Converting a JavaScript list of objects into an index lookup object is a common algorithm. Using the ES6 syntax it is possible to sorten the classic approach that used a `for` loop.

Building an indexed object from an array of objects in JavaScript

ES6 can be short and precise. Look at this tiny algorithm that I use quite regularly. It converts a list of objects to a lookup table / index / object that can be access the entries more effiently for repetitve lookup tasks.

The goal I have a list of objects (mediaList) and want to create a look up table from it by one of it's properties (id), assuming that this property is unique.

Input

const mediaList = [
  { duration: 514, id: 'vO4vti9JJ2Q', type: 'youtube' },
  { duration: 3531, id: 'ozD4h9HCHOY', type: 'youtube' },
]

Output

const lookupTable = {
  vO4vti9JJ2Q: { duration: 514, id: 'vO4vti9JJ2Q', type: 'youtube' },
  ozD4h9HCHOY: { duration: 3531, id: 'ozD4h9HCHOY', type: 'youtube' },
}

The old way

This is the code I used to write in ES5.

var lookupTable = {};
for (var i = 0; i < mediaList.length; i++) {
  lookupTable[id] = mediaList[i].id
}

I never thought about changeing this approach until I discovered Death of the For Loop and similar articles. The arguments for a functional coding style are quite complelling for this problem. It decreases the characters you have write and the cognitive load when reading code, by decreasing the number of items that your mind has to track. To achieve this you need to get familiar with the ES6 syntax, now available in modern browsers or through polyfills.

The new way

The look up table in ES6 code

const lookupTable = mediaList.reduce(
    (acc, media) => ({ ...acc, { [media.id]: media } })
    , {})

The Disection

Starting with the inital for loop

var lookupTable = {};
for (var i = 0; i < mediaList.length; i++) {
  lookupTable[id] = mediaList[i]
}

The ES6 code can be construted part by part by replacing it with ES6 syntax.

Step 1, replacing the for loop with an array .reduce() function.

const lookupTable = mediaList.reduce(
  function(acc, media) {
    const newItem = {};
    newItem[media.id] = media;
    return Object.assign( acc, newItem);
  },
  {} // initial value of `acc`, the accumulator object
)

Step 2, the object {} creation is replaced with the sorter object literal syntax { [attrName]: val }

const lookupTable = mediaList.reduce(
  function(acc, media) {
    return Object.assign( acc, { [media.id]: media });
  },
  {}
)

Step 3, the function call with the shorter => arrow function

const lookupTable = mediaList.reduce(
  (acc, media) => Object.assign( acc, { [media.id]: media }),
  {}
)

Step 4, and the Object.assign with the sorter ... object destructuring

const lookupTable = mediaList.reduce(
    (acc, media) => ({ ...acc, { [media.id]: media } })
    , {})

Alternative with smaller transpile footprint

Since the spread operator takes up a lot of transpiled code I use another variant of this pattern.

const lookupTable = mediaList.reduce(
    (acc, media) => Object.assign(acc, { [media.id]: media }),
    {} 
)

But if you read this, most likely in a couple of years from when I wrote this, you will not need to transpile the code anymore and you can savely ignore this paragraph.

Conclusion

Admittedly it is hard to see with this example alone, but my experinece showed me that functional ES6 code

  • deceased my code length, and
  • lowerd my error rate.

The End