Using Array reduce

By  on  

Every developer who specializes in any programming language will tell you there's a powerful tool the language provides that they rarely use and wish they knew more about. For me, it's Array.prototype.reduce. I quite enjoy the other Array methods like map, filter, and find, but reduce is one that I knew was powerful but never really had much use for.

It wasn't until I was refactoring some of the Firefox DevTools Debugger code that I found a great use case for reduce -- one I plan on using in the future.

Methods like forEach and map were created to avoid side effects, and reduce is no exception. In this case, however, reduce can return an Object other than an Array. Take this case for example:

// Samples sources
const sources = [
  {
    id: "server1.conn13.child1/39",
    url: "https://davidwalsh.name/"
  },
  {
    id: "server1.conn13.child1/37",
    url: "https://davidwalsh.name/util.js"
  }
];

// Return an object of sources with the keys being "id"
const sourcesMap = sources.reduce((map, source) => {
  map[source.id] = source
  return map;
}, {});

In the example above, we take an array of Source objects and return a single object literal with each Source's id as the key:

{
  "server1.conn13.child1/39": {
    "id": "server1.conn13.child1/39",
    "url": "https://davidwalsh.name/"
  },
  "server1.conn13.child1/37": {
    "id": "server1.conn13.child1/37",
    "url": "https://davidwalsh.name/util.js"
  }
}

Note that the {}, which is the last argument to reduce, is starting/default object to be returned. If there were no items in the array, {} would be returned. Also appreciate that an array method returns an object literal and not a modified array!

It's crazy that I've not used reduce more, but that's just life in our industry -- we all have a few APIs we just haven't used much of. What feature of JavaScript have you frequently seen but not used?

Recent Features

  • By
    CSS @supports

    Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS.  What we end up doing is repeating the same properties multiple times with each browser prefix.  Yuck.  Another thing we...

  • By
    How to Create a RetroPie on Raspberry Pi – Graphical Guide

    Today we get to play amazing games on our super powered game consoles, PCs, VR headsets, and even mobile devices.  While I enjoy playing new games these days, I do long for the retro gaming systems I had when I was a kid: the original Nintendo...

Incredible Demos

  • By
    Highlight Table Rows, Columns, and Cells Using MooTools 1.2.3

    Row highlighting and individual cell highlighting in tables is pretty simple in every browser that supports :hover on all elements (basically everything except IE6). Column highlighting is a bit more difficult. Luckily MooTools 1.2.3 makes the process easy. The XHTML A normal table. The cells...

  • By
    Drag & Drop Elements to the Trash with MooTools 1.2

    Everyone loves dragging garbage files from their desktop into their trash can. There's a certain amount of irony in doing something on your computer that you also do in real life. It's also a quick way to get rid of things. That's...

Discussion

  1. Carlos Saldaña

    also reduce is more faster than map when counting

    https://jsbench.me/5ujuudpnmh

  2. Andrzej

    The only way to use forEach without side effects is to immediately return. Any other code in callback will cause side effect.

  3. Leo Lanese

    or you could use rxjs:

    import { from, of, zip } from 'rxjs';
    import { groupBy, mergeMap, toArray } from 'rxjs/operators';
    
    const sources = [
      {
        id: "idleo",
        url: "urlleo"
      },
      {
        id: "idtom",
        url: "urltom"
      }
    ];
    
    from(sources)
      .pipe(
        groupBy(n => n.id, p => p.url),
        mergeMap(group => zip(of(group.key), group.pipe(toArray())))
      )
      .subscribe(console.log);
    
  4. Forrest Akin

    Yes, reduce all the things! This object creation pattern is so prevalent, I typically just use keyBy()

    const set = (target, key, value) => (target[key] = value, target)
    const keyBy = (key, items) =>
        items.reduce((map, item) => set(map, item[key], item), {})
    

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!