DEV Community

Discussion on: Explain REDUCE Like I'm Five

Collapse
 
brnkrygs profile image
Brian Krygsman

Hi!

First post on this awesome site, hope you don't mind a late response... (this is a fantastic question :) )

My favourite way of thinking about reduce is that its useful for changing the shape of a collection.

Why might changing the shape of a collection be useful?

Some reasons:

1. You want to collapse a collection of values into a single one

The classic example here is calculating a sum of a collection of numbers:

Turn [1,2,3,4] into 10.

by using reduce like this (as seen in the comment above):

[1,2,3,4].reduce(( sum, item ) => sum+=item, 0 );

2. You want to collect a list of records under a shared category

This case is a little more real-world - you have a collection of records that you need to group or categorize in some way for display or calculation, which means you might need to add a nesting level.

That is, turn this:

[
  { id: 1, category: 'fruit', name: 'Apple' },
  { id: 2, category: 'vegetable', name: 'Carrot' },
  { id: 3, category: 'grain', name: 'Oats' },
  { id: 4, category: 'fruit', name: 'Pear' }
]

Into this (notice the new nesting level... and its a dictionary now, not an array!):

{
  'fruit': [
    { id: 1, category: 'fruit', name: 'Apple' },
    { id: 4, category: 'fruit', name: 'Pear' }
  ],
  'vegetable': [
    { id: 2, category: 'vegetable', name: 'Carrot' }
  ],
  'grain': [
    { id: 4, category: 'fruit', name: 'Pear' }
  ]
}

By using reduce like this:

const products = [
  { id: 1, category: 'fruit', name: 'Apple' },
  { id: 2, category: 'vegetable', name: 'Carrot' },
  { id: 3, category: 'grain', name: 'Oats' },
  { id: 4, category: 'fruit', name: 'Pear' },
];

const categorizedProducts = products
  .reduce(( currentCollection, item ) => {

    // Check if we have this key or not. If not, initialize a child array
    if( !currentCollection[item.category]){
      currentCollection[item.category] = [];
    }

    // Collect this item under the right category
    currentCollection[item.category].push( item );

    // Continue building on this collection
    return currentCollection;
  }, {});

(feel free to play with it here: repl.it/@brnkrygs/Exploring-Reduce)

As others have noted, you can use reduce to implement map and filter as well, and you might be able to see how...

When you reduce a collection and push each item directly onto your result collection (or "accumulator"), but change just that item in some way, it's a map (e.g. capitalize the name of each item).

When you reduce a collection and inspect each item to decide if you want to push it onto your result collection or skip it, that is filter.

So...

  1. reduce changes the shape of the collection as a whole
  2. map changes individual items in a collection
  3. filter excludes individual items from a collection