Reduce made easy
Pages 616
- Home
- Home
- 10 Steps To Plan Better So You Can Write Less Code
- 5 Steps to organizing a successful Campsite event
- Academic Honesty Policy
- accessibility 101
- Accessing the database from your frontend
- Adding Environment Variables
- Adding Snippets In Sublime Text
- Adding Snippets To Sublime Text
- Advantages and Disadvantages of Javascript
- Algorithm Arguments Optional
- Algorithm Binary Agents
- Algorithm Boo who
- Algorithm Caesars Cipher
- Algorithm Check for Palindromes
- Algorithm Chunky Monkey
- Algorithm Confirm the Ending
- Algorithm Convert HTML Entities
- Algorithm Diff Two Arrays
- Algorithm DNA Pairing
- Algorithm Drop It
- Algorithm Everything be True
- Algorithm Exact Change
- Algorithm Factorialize a Number
- Algorithm Falsy Bouncer
- Algorithm Find The Longest Word in a String
- Algorithm Finders Keepers
- Algorithm Friendly Date Ranges
- Algorithm Inventory Update
- Algorithm Make a Person
- Algorithm Map the Debris
- Algorithm Missing letters
- Algorithm Mutations
- Algorithm No Repeats Please
- Algorithm Pairwise
- Algorithm Pig Latin
- Algorithm Repeat a String Repeat a String
- Algorithm Return Largest Numbers in Arrays
- Algorithm Reverse a String
- Algorithm Roman Numeral Converter
- Algorithm Search and Replace
- Algorithm Seek and Destroy
- Algorithm Slasher Flick
- Algorithm Smallest Common Multiple
- Algorithm Sorted Union
- Algorithm Spinal Tap Case
- Algorithm Steamroller
- Algorithm Style Guide
- Algorithm Sum All Numbers in a Range
- Algorithm Sum All Odd Fibonacci Numbers
- Algorithm Sum All Primes
- Algorithm Symmetric Difference
- Algorithm Title Case a Sentence
- Algorithm Truncate a String
- Algorithm Validate US Telephone Numbers
- Algorithm Where art thou
- Algorithm Where do I belong
- Algorithms Merge Sort
- Angular Resources
- Arithmetic Operators
- Array.isArray
- August 2015 Improvements
- August Live Stream
- Back End Project Resources
- Backend file structure
- beta
- Bobby Tables
- Bonus SocketIO
- Bootstrap
- bot announce
- botdemo
- botintro
- Brownie Points
- Browser Storage
- Camper News
- camperbot
- Campsites
- Capitalize First Letter Of String
- chai
- chai assert
- chai cheat
- Challenge Access Array Data with Indexes
- Challenge Access Multi Dimensional Arrays With Indexes
- Challenge Accessing Nested Arrays In Json
- Challenge Accessing Nested Objects In Json
- Challenge Accessing Objects Properties With Bracket Notation
- Challenge Accessing Objects Properties With The Dot Operator
- Challenge Accessing Objects Properties With Variables
- Challenge Add a Negative Margin to an Element
- Challenge Add a Submit Button to a Form
- Challenge Add Alt Text to an Image for Accessibility
- Challenge Add Borders Around your Elements
- Challenge Add Different Margins to Each Side of an Element
- Challenge Add Different Padding to Each Side of an Element
- Challenge Add Elements within your Bootstrap Wells
- Challenge Add Font Awesome Icons to all of our Buttons
- Challenge Add Font Awesome Icons to our Buttons
- Challenge Add ID Attributes to Bootstrap Elements
- Challenge Add Images to your Website
- Challenge Add New Properties to a JavaScript Object
- Challenge Add Placeholder Text to a Text Field
- Challenge Add Rounded Corners with a Border Radius
- Challenge Add Two Numbers with JavaScript
- Challenge Add your JavaScript Slot Machine Slots
- Challenge Adding A Default Option In Switch Statements
- Challenge Adjust the Margin of an Element
- Challenge Adjusting the Padding of an Element
- Challenge Appending Variables to Strings
- Challenge Apply the Default Bootstrap Button Style
- Challenge Assignment With A Returned Value
- Challenge Assignment with Divided by Equals
- Challenge Assignment with Minus Equals
- Challenge Assignment with Plus Equals
- Challenge Assignment with Times Equals
- Challenge Bring your JavaScript Slot Machine to Life
- Challenge Build JavaScript Objects
- Challenge Call out Optional Actions with Button Info
- Challenge Center Text with Bootstrap
- Challenge Chaining If Else Statements
- Challenge Change Text Inside an Element Using jQuery
- Challenge Change Text with Click Events
- Challenge Change the Color of Text
- Challenge Change the CSS of an Element Using jQuery
- Challenge Change the Font Size of an Element
- Challenge Check Radio Buttons and Checkboxes by Default
- Challenge Check the Length Property of a String Variable
- Challenge Clone an Element Using jQuery
- Challenge Comment out HTML
- Challenge Comment your JavaScript Code
- Challenge Comparison With The Equality Operator
- Challenge Comparison With The Greater Than Equal To Operator
- Challenge Comparison With The Greater Than Operator
- Challenge Comparison With The Inequality Operator
- Challenge Comparison With The Less Than Equal To Operator
- Challenge Comparison With The Less Than Operator
- Challenge Comparison With The Strict Equality Operator
- Challenge Comparison With The Strict Inequality Operator
- Challenge Comparisons With The Logical And Operator
- Challenge Comparisons With The Logical Or Operator
- Challenge Concatenate Strings with .concat
- Challenge Concatenating Strings with Plus Operator
- Challenge Concatenating Strings with the Plus Equals Operator
- Challenge Condense arrays with reduce
- Challenge Construct JavaScript Objects with Functions
- Challenge Constructing Strings with Variables
- Challenge Convert JSON Data to HTML
- Challenge Count Backwards With a For Loop
- Challenge Create a Block Element Bootstrap Button
- Challenge Create a Bootstrap Button
- Challenge Create a Bootstrap Headline
- Challenge Create a Bootstrap Row
- Challenge Create a Bulleted Unordered List
- Challenge Create a Class to Target with jQuery Selectors
- Challenge Create a Custom Heading
- Challenge Create a Form Element
- Challenge Create a JavaScript Slot Machine
- Challenge Create a Set of Checkboxes
- Challenge Create a Set of Radio Buttons
- Challenge Create a Text Field
- Challenge Create an Ordered List
- Challenge Create Bootstrap Wells
- Challenge Create Decimal Numbers with JavaScript
- Challenge Declare JavaScript Objects as Variables
- Challenge Declare JavaScript Variables
- Challenge Declare String Variables
- Challenge Decrement a Number with Javascript
- Challenge Delete HTML Elements
- Challenge Delete Properties from a JavaScript Object
- Challenge Delete your jQuery Functions
- Challenge Disable an Element Using jQuery
- Challenge Ditch Custom CSS for Bootstrap
- Challenge Divide One Number by Another with JavaScript
- Challenge Escape Sequences in Strings
- Challenge Escaping Literal Quotes in Strings
- Challenge Fill in the Blank with Placeholder Text
- Challenge Filter Arrays with filter
- Challenge Find Numbers with Regular Expressions
- Challenge Find the Length of a String
- Challenge Find White Space with Regular Expressions
- Challenge Finding a Remainder in Javascript
- Challenge Generate Random Fractions with JavaScript
- Challenge Generate Random Whole Numbers with JavaScript
- Challenge Generate Random Whole Numbers within a Range
- Challenge Get Geo location Data
- Challenge Get JSON with the jQuery getJSON Method
- Challenge Give a Background Color to a Div Element
- Challenge Give Each Element a Unique ID
- Challenge Give your JavaScript Slot Machine some stylish images
- Challenge Global Scope And Functions
- Challenge Global Vs Local Scope In Functions
- Challenge Headline with the h2 Element
- Challenge House our page within a Bootstrap Container Fluid Div
- Challenge Import a Google Font
- Challenge Increment a Number with Javascript
- Challenge Inform with the Paragraph Element
- Challenge Inherit Styles from the Body Element
- Challenge Initializing Variables with the Equal Operator
- Challenge Introducing Else If Statements
- Challenge Introducing Else Statements
- Challenge Introducing Javascript Object Notation Json
- Challenge Invert Regular Expression Matches with JavaScript
- Challenge Iterate Odd Numbers With a For Loop
- Challenge Iterate over Arrays with map
- Challenge Iterate Through An Array With A For Loop
- Challenge Iterate with JavaScript For Loops
- Challenge Iterate with JavaScript While Loops
- Challenge Join Strings with .join
- Challenge Label Bootstrap Buttons
- Challenge Label Bootstrap Wells
- Challenge Learn how Script Tags and Document Ready Work
- Challenge Line up Form Elements Responsively with Bootstrap
- Challenge Link to External Pages with Anchor Elements
- Challenge Local Scope And Functions
- Challenge Make Circular Images with a Border Radius
- Challenge Make Dead Links using the Hash Symbol
- Challenge Make Images Mobile Responsive
- Challenge Make Instances of Objects with a Constructor Function
- Challenge Make Object Properties Private
- Challenge Make Unique Objects by Passing Parameters to our Constructor
- Challenge Manipulate Arrays With pop()
- Challenge Manipulate Arrays With push()
- Challenge Manipulate Arrays With shift()
- Challenge Manipulate Arrays With unshift()
- Challenge Manipulate JavaScript Objects
- Challenge Modify Array Data With Indexes
- Challenge Multiple Identical Options In Switch Statements
- Challenge Multiply Two Numbers with JavaScript
- Challenge Nest an Anchor Element within a Paragraph
- Challenge Nest Many Elements within a Single Div Element
- Challenge Nest one Array within Another Array
- Challenge Nesting For Loops
- Challenge Override All Other Styles by using Important
- Challenge Override Class Declarations by Styling ID Attributes
- Challenge Override Class Declarations with Inline Styles
- Challenge Override Styles in Subsequent CSS
- Challenge Passing Values To Functions With Arguments
- Challenge Perform Arithmetic Operations on Decimals with JavaScript
- Challenge Prefilter JSON
- Challenge Prioritize One Style Over Another
- Challenge Quoting Strings with Single Quotes
- Challenge Remove an Element Using jQuery
- Challenge Remove Classes from an element with jQuery
- Challenge Render Images from Data Sources
- Challenge Replacing If Else Chains With Switch
- Challenge Responsively Style Checkboxes
- Challenge Responsively Style Radio Buttons
- Challenge Return A Value From A Function With Return
- Challenge Return Early Pattern For Functions
- Challenge Returning Boolean Values From Functions
- Challenge Reverse Arrays with reverse
- Challenge Save your Code Revisions Forever with Git
- Challenge Say Hello to HTML Elements
- Challenge Selecting From Many Options With Switch Statements
- Challenge Set the Font Family of an Element
- Challenge Set the ID of an Element
- Challenge Sift through Text with Regular Expressions
- Challenge Size your Images
- Challenge Solution Template
- Challenge Sort Arrays with sort
- Challenge Specify How Fonts Should Degrade
- Challenge Split Strings with split
- Challenge Split your Bootstrap Row
- Challenge Store Multiple Values in one Variable using JavaScript Arrays
- Challenge Storing Values with the Equal Operator
- Challenge Style Multiple Elements with a CSS Class
- Challenge Style Text Inputs as Form Controls
- Challenge Style the HTML Body Element
- Challenge Subtract One Number from Another with JavaScript
- Challenge Target a Specific Child of an Element Using jQuery
- Challenge Target Elements by Class Using jQuery
- Challenge Target Elements by ID Using jQuery
- Challenge Target Even Numbered Elements Using jQuery
- Challenge Target HTML Elements with Selectors Using jQuery
- Challenge Target the Children of an Element Using jQuery
- Challenge Target the Parent of an Element Using jQuery
- Challenge Target the same element with multiple jQuery Selectors
- Challenge Taste the Bootstrap Button Color Rainbow
- Challenge Testing Objects For Properties
- Challenge Trigger Click Events with jQuery
- Challenge Turn an Image into a Link
- Challenge Uncomment HTML
- Challenge Understand Boolean Values
- Challenge Understand String Immutability
- Challenge Understanding Case Sensitivity in Variables
- Challenge Understanding Uninitialized Variables
- Challenge Updating Object Properties
- Challenge Use a CSS Class to Style an Element
- Challenge Use Abbreviated Hex Code
- Challenge Use an ID Attribute to Style an Element
- Challenge Use appendTo to Move Elements with jQuery
- Challenge Use Bracket Notation to Find the First Character in a String
- Challenge Use Bracket Notation to Find the Last Character in a String
- Challenge Use Bracket Notation to Find the Nth Character in a String
- Challenge Use Bracket Notation to Find the Nth to Last Character in a String
- Challenge Use Clockwise Notation to Specify the Margin of an Element
- Challenge Use Clockwise Notation to Specify the Padding of an Element
- Challenge Use Comments to Clarify Code
- Challenge Use Conditional Logic with If Else Statements
- Challenge Use CSS Selectors to Style Elements
- Challenge Use Hex Code for Specific Colors
- Challenge Use Hex Code for Specific Shades of Gray
- Challenge Use Hex Code to Color Elements Blue
- Challenge Use Hex Code to Color Elements Gray
- Challenge Use Hex Code to Color Elements Green
- Challenge Use Hex Code to Color Elements Red
- Challenge Use Hex Code to Color Elements White
- Challenge Use Hex Code to Mix Colors
- Challenge Use HTML5 to Require a Field
- Challenge Use jQuery to Modify the Entire Page
- Challenge Use Responsive Design with Bootstrap Fluid Containers
- Challenge Use RGB to Color Elements Blue
- Challenge Use RGB to Color Elements Gray
- Challenge Use RGB to Color Elements Green
- Challenge Use RGB to Color Elements Red
- Challenge Use RGB to Color Elements White
- Challenge Use RGB to Mix Colors
- Challenge Use RGB values to Color Elements
- Challenge Use Spans for Inline Elements
- Challenge Use the Bootstrap Grid to Put Elements Side By Side
- Challenge Use the Javascript Console
- Challenge Using Objects For Lookups
- Challenge Using typeof
- Challenge Warn your Users of a Dangerous Action
- Challenge Write Reusable JavaScript with Functions
- Check if an element is hidden using jQuery
- Check if element is hidden js or jquery
- Checkpoint Convert Celsius to Fahrenheit
- Checkpoint Counting Cards
- Checkpoint Golf Code
- Checkpoint Profile Lookup
- Checkpoint Record Collection
- Checkpoint Shopping List
- Checkpoint Stand In Line
- Checkpoint Word Blanks
- Clear Your Browser's Local Storage
- Clone A Specific Branch
- code case
- code formatting
- Code of Conduct
- Coding Help
- CONTRIBUTING
- Contributions Guide with Typo Demo
- Create, Upload and Link Animated GIF Image
- Creating a new API endpoint
- Creating a new directive
- Creating a New Github Issue
- Creating a new route
- css
- css selectors
- Currying
- dau
- debugging
- Debugging JavaScript with Browser DevTools
- Deleting A Branch
- demo trim
- Develop Back End Project locally and run on c9.io
- Disable Code Auto Run
- Django Start Project
- Dotnet
- Dynamic URLs using $routeParams
- Edit or Delete message
- Elixir
- emoji
- Epilogue
- equality vs identity
- example
- Fixing exports.update
- For loops Explained
- Free Code Camp Back End Development Certification
- Free Code Camp completion language requirements
- Free Code Camp Data Visualization Certification
- Free Code Camp Deployment Workflow
- Free Code Camp Front End Development Certification
- Free Code Camp Full Stack Development Certification
- Free Code Camp is an open source community distributed across many platforms
- Free Code Camp JavaScript Style Guide
- Free Code Camp logo
- Free Code Camp's Privacy Policy
- Front End Project Use the Twitchtv JSON API
- Frontend file structure
- Functional Programming Higher Order Functions
- Get info about the current user
- Get Screen Size In Pixels
- Get started with Node_js
- Getting a coding job
- Git Amend Last
- Git Blame
- Git Change the URL of a remote repository
- Git Checkout A Remote Branch
- Git Delete a Branch both locally and remotely
- Git Force Git to overwrite local files on pull
- git merge
- Git Pull Vs Git Fetch
- Git Push Local To Remote Repository
- git rebase
- Git Resources
- Git Shortcut
- Git Undo Redo A Commit
- Gitter
- Gitter Moderation Policy
- global variables
- Go
- Grunt
- Guide Online Contribution
- Guide to Back End Projects Table of Contents
- Guide to Submitting Posts to Free Code Camp Medium Publication
- Gulp Basics
- Help I've Found a Bug
- Help Rooms
- Heroku Deployment Guide
- Higher Order functions
- How Free Code Camp works
- How FreeCodeCamp Nonprofit Projects work
- How GitHub Issue Moderators AKA Issue Mods Work
- How JSONP is different from JSON
- How Long Free Code Camp Takes
- How to add Free Code Camp to my LinkedIn profile
- How to best use the Global Control Shortcuts for Mac
- How to clear specific values from your browser's local storage
- How to clone the FreeCodeCamp website on a Windows pc
- How To Contribute To The Wiki
- How to create a Campsite for your city
- How To Create A Pull Request for Free Code Camp
- How to deploy a website without writing any code at all
- How To Fork And Maintain a Local Instance of Free Code Camp
- How to Get Help on Gitter
- How to get help when you get stuck
- How to get the MEAN stack running locally on OSX
- How To Install Clementine
- How to install Screenhero
- How to know who is in charge of your Campsite on Facebook
- How To Log In To Your Local FCC Site
- how to post code
- How to Rename a Local Branch
- How to share your workspace selfie with FreeCodeCamp on instagram
- How to start when you are stuck (I)
- How to start when you are stuck (II)
- How to start when you are stuck (III)
- How to use the Free Code Camp Wiki
- How you can get to Inbox Zero with Gmail shortcuts
- How you can help to stimulate your city's Campsite on Facebook
- How you can reach the Free Code Camp team to interview them for your publication
- Html and CSS Cheat Sheet
- html elements
- If Free Code Camp is free, how does it make money
- Ignore Files Committed To Git Repo
- IIFE
- Install Django Flask
- Installing WordPress Locally on Mac
- Intro to Yeoman Angular Fullstack Back End Projects
- isLoggedInAsync
- Java
- Java Basics
- Java Introduction
- Java Loops
- Java Resources
- Javascript Callback Functions
- JavaScript Truth Table
- jQuery
- js arguments
- js Array prototype concat
- js Array prototype every
- js Array prototype filter
- js Array prototype forEach
- js Array prototype indexOf
- js Array prototype join
- js Array prototype lastIndexOf
- js Array prototype map
- js Array prototype pop
- js Array prototype push
- js Array prototype reduce
- js Array prototype reverse
- js Array prototype shift
- js Array prototype slice
- js Array prototype some
- js Array prototype sort
- js Array prototype splice
- js Array prototype toString
- js Boolean
- js closures
- JS Comparison Operators
- JS Current URL
- js falsy
- js for in loop
- js for loop
- js for of loop
- js functions
- JS Get Timestamp
- js Global Object
- js immutable
- js loops
- JS Regex Resources
- JS Resources
- js Scopes
- JS Strict Mode
- js String prototype charAt
- js String prototype charCodeAt
- js String prototype concat
- js String prototype indexOf
- js String prototype lastindexOf
- js String prototype match
- js String prototype replace
- js String prototype slice
- js String prototype split
- js String prototype substr
- js String prototype substring
- js String prototype toLowerCase
- js String prototype toUpperCase
- js ternary
- js truthy
- js undefined
- jsonp
- Know it all
- Known Issues With Codepen
- latex
- Learn the basics of the VIM editor
- Linking Your Account with GitHub
- Linux
- List of Free Code Camp city based Campsites
- Loop Protect
- Map
- materializecss framework as a bootstrap alternative
- Math.max
- Math.min
- Math.pow
- medium example wiki article
- More useful APIs
- Mostaganem
- Object.getOwnPropertyNames
- Object.keys
- October 2015 Improvements
- October 2015 Summit Agenda
- Official Free Code Camp Chat Rooms
- ooda
- Other resources that Free Code Camp recommends to nonprofits
- Page redirects using javascript
- Pair programming and why it is special
- parseInt
- Permutations
- Php
- Politica De Honestidad Academica
- Programming Fundamental
- Programming Methodology
- Promises
- Pseudoclassical class definition OOp
- Pull Request Contribute
- PULL_REQUEST_TEMPLATE
- Python
- Python Basics
- Python Functions
- Python Introduction
- Python More Builtin Types
- Python Operators
- Python Resources
- Quick tip keep data in sync
- README
- Reduce made easy
- Refresh Your Browser Cache
- Registering your Nonprofit to Raise Donations through Free Code Camp Commit
- Restrict a page to authenticated users
- RTFM
- Ruby
- Ruby Introduction
- Run Apache Server On A Mac
- Saturday Summit August 2015
- Saturday Summit December 2015
- Saturday Summit November 2015
- Saturday Summit October 2015
- Searching for Your Issue on Github
- Seed data
- Select Issues for Contributing Using Labels
- Setting Up A React ES6 Webpack Project
- Site Improvements August 2015
- Site Improvements October 2015
- Slack
- Spanish Translation Terminology
- staging
- Start Here
- Streaks
- Stream Your Coding Sessions on Twitch.tv
- String.fromCharCode
- String.length
- Swashbuckle Swagger Operation Alphabetical Order
- The main advantages of Free Code Camp
- The Return Early Pattern
- Tips on How To Become A Good Pair Programmer
- topic
- Translating Free Code Camp into Your Native Language
- Translations Guide
- Twitch
- up_and_running_with_sass
- update
- Updates February 11 2016
- using anonymous self executing functions for private namespacing in your js apps
- Using browsec for securing your connection to fcc
- Using Github Pages for your front end development projects
- video demo
- wat
- Web Development in Python
- Web Resources
- What exactly Free Code Camp does
- What pair programming is and why it is special
- What the main advantages of Free Code Camp are
- What the style guide for Algorithms is
- What to do if you speak a language that Free Code Camp does not yet support
- What you will learn, and in what sequence you will learn it
- Why does Free Code Camp use JavaScript instead of Ruby or Python
- Why you need Free Code Camp
- Why You Should Try Pair Programming
- wiki js template
- Wiki Style Guide
- World Language Chat Rooms
- Write and Run ES6 Code in Browser
- writing a markdown file using atom
- Writing great git commit message
- Show 601 more pages…
New to Free Code Camp?
JS Concepts
JS Language Reference
- arguments
- Array.prototype.filter
- Array.prototype.indexOf
- Array.prototype.map
- Array.prototype.pop
- Array.prototype.push
- Array.prototype.shift
- Array.prototype.slice
- Array.prototype.some
- Array.prototype.toString
- Boolean
- for loop
- for..in loop
- for..of loop
- String.prototype.split
- String.prototype.toLowerCase
- String.prototype.toUpperCase
- undefined
Other Links
Clone this wiki locally
Using Array.prototype.reduce()
to Reduce Conceptual Boilerplate for Problems on Arrays
That's quite a mouthful! It could have just been titled as Use Array.prototype.reduce()
to Solve Array Problems Easily or Array.prototype.reduce()
FTW!. That would have been so much easier to read and parse.
But It was not. Loops in JavaScript are just like that. They are not terse, they make you beat around the bush for a while. As the joke goes, two things are most difficult in computer science - cache invalidation, naming things, and off-by-one error.
And then there is the danger of writing asynchonous code inside a for loop without using closure from IIFE.
This article would start with a claim - that you can avoid using a for-loop or while-loop to solve any Array
related problems.
Instead, you can solve all of them using Array.prototype.reduce()
. If you wish to read forward; do make sure you know about recursive functions, and some of the cool functional tools like Array.prototype.map()
or Array.prototype.filter()
.
Grand claims require grand evidence. So let's demonstrate how we can get accustomed with using reduce()
.
It's time you knew, that, if you haven't solved the FreeCodeCamp algorithm scripting sections, you might want to hold off on reading this next part. Some of the examples could very well match those problems.
This is the cliched spoiler alert; to make sure you give those problems an honest attempt and not take a peek at the solutions before you have even tried.
Also, if you already understand it well enough, perhaps you would like to review this piece of writing and provide feedback.
Can I Reduce Any Array-related Problem?
Yes, you can! In fact, the problem doesn't even have to have an Array - it just has to be a problem, where you can create an intermediate array.
Let's take an example. It's quite common to create a slug url from standard white-spaced string such as news headlines, blog article headings or even questions on Q&A forums.
Say, we have to write a utility function, that creates this slug. You could probably write something like this:
function createSlug(str){
return str.split(" ").reduce(function(prev, next){
return prev.concat([next.toLowerCase()]);
}, [])
.join("-");
}
Don't take my word for it! Go ahead, and test it out in your console with some input like "Leo Finally Wins a Freaking Oscar!" See what it returns. I will wait...done? Ok, moving on.
Yes, it's not a robust implementation. It does not take care of some edge cases, also it assumes the joining should happen with "-"
.
But it's a start. Notice how the usage of reduce
takes the boilerplate out of your way -- the action happens only at the line:
return prev.concat([next.toLowerCase()]);
That's the core of the functionality we want. In fact, we are so assured of its awesomeness, that we start the function
body with a return
statement!
You might very well imagine that, this looks like dark magic. Make sure that is not a knee-jerk reaction, because you are too used to writing loops. Just give it five minutes!
If the above code was not clear, you need to understand how reduce
works. And by understand, I mean, know it like the back of your hand.
But I Do NOT Understand Reduce At All!
Well, fear not! You are about to be a reduce
Ninja in the next few minutes.
Every JavaScript function has three things you need to know, to understand how the function works:
- The input
- The output
- The execution context
Yes, I can see you opening the official MDN documentation in a new tab! It's ok, go read that first. I am serious, this is no joke.
You should always start at the official documentation to understand something.
Good, now that you are confused with the prev
and next
inside the callback; you are ready to follow the text here.
Array.prototype.reduce()
takes a callback and initial value as input arguments (The initial value is important. A lot of developers forget to provide the initial value correctly; and screw up their code).
As you must have seen in the documentation, it takes a few additional but optional arguments as well. But more on that later. Assuming arr
is an arbitrary array.
arr.reduce(function(){}, initialValue);
Now, let's have a closer look at the callback function, which is the first argument of reduce
. This callback, in turn, takes two arguments.
These two arguments are called in the official documentation as prev
and next
. Personally, I don't think those names do justice to their true nature.
So, throughout this text, we would be referring to them as acc
, to represent accumulated value; and item
, to denote the current item being accessed.
With these so far, here's what a reduce
should look like:
arr.reduce(function(acc, item){
/* here you have to complete the function */
}, initialValue);
Now, let's find out what would the value of these acc
and item
are. We have mentioned earlier that the reduce
is a replacement for iterative constructs.
It stands to reason that reduce
would take your custom callback function; and iterate over the Array on which reduce
has been invoked.
Instead of describing these, let's ask the JS execution engine what these are!
var arr = [10, 20, 30, 60];
arr.reduce(function(acc, item){
console.log(acc, item);
}, 0);
Executing the above in browser or Node console would give you this as output:
0 10
undefined 20
undefined 30
undefined 60
Notice the number of outputs are same as number of elements in the Array [10, 20, 30, 60]
. In fact, it prints out the elements of the Array!
So, we can deduce that reduce()
takes your custom callback and executes it on each element of the Array. While doing so, it makes the current item available to the custom callback as item
argument.
But what about acc
? We see that other than the first line, when item = 10
, it is undefined
. In the first line, which corresponds to the first iteration, its value is same as initialvalue
.
In short, our acc
accumulator, is not accumulating!
But then, how do we make it accumulate? Let's try executing this:
var arr = [10, 20, 30, 60];
arr.reduce(function(acc, item){
console.log(acc, item);
return acc;
}, 0);
This time the output changes to:
0 10
0 20
0 30
0 60
As you can see, the value of acc
would remain constant throughout. And that is expected - we are not altering the value of acc
anywhere in the custom callback. We return whatever reduce
makes available at a given iteration.
But we did realize something - the value of acc
for current iteration, would be the return
value from custom callback from previous iteration. And ultimately, when the iteration is over, the final value of acc
would be returned by reduce
call.
This leaves only one important part in our understanding - the value of execution context, or this
!
So, we again approach our friendly neighbor, the JS console and execute this:
var arr = [10, 20, 30, 60];
arr.reduce(function(acc, item){
console.log(acc, item, this);
return acc;
}, 0);
If you are in strict mode, it would return undefined
as value of this
. Otherwise, in-browser, it would point to window
object as this
.
Can we override and set it on our own, using bind
? Sure! just use bind
with the callback:
var arr = [10, 20, 30, 60];
arr.reduce(function(acc, item){
console.log(acc, item, this);
return acc;
}.bind(arr), 0);
I have bound the array arr
itself; but you can set it to any object in your environment.
Understanding Reduce
Let's summarize our understanding of this reduce
function for easy reference:
- Reduce takes a custom callback as its first argument, and some initial value as its second argument.
- It's important we don't forget about the second argument, the initial value; and we explicitly set it while using it.
- The input arguments to the custom callback is accumulated value
acc
; and the current item in Array,item
. - The value of
acc
for next iteration would be the returned value from inside the callback, in current iteration. - Whole point of using
reduce()
is to form theacc
properly; to return it finally from thereduce()
call.
Don't you try remembering them by cramming! Instead, let's remember them by applying them in real code.
Using Reduce
Let's start a simple Array operation off the top-of our head - finding maximum in an Array
For the sake of brevity, I am assuming it's an integer Array.
To form a solution, we need to think of how to form the acc
as reduce
takes our callback and iterates over the Array.
An idea I find helpful, is to think in terms of loop-invariants. We want to come up with a formulation that no matter what the size or content of the Array; acc
should always have the maximum value so far.
Say, My Array is [20, 50, 5, 60]
. After two iterations; item
would be 5
and acc
should be max(20, 50) = 50
.
The only way acc
always gets the maximum of subarray traversed so far, is if we always pick maximum of current item
and acc
- and return he winner!
So, here's what the function would look like:
var arr = [20, 50, 5, 60];
arr.reduce(function(acc, item){
return Math.max(acc, item);
}, 0);
It could be tempting to rewrite it as follows, in tandem with functional programming principles;
var arr = [20, 50, 5, 60];
arr.reduce(Math.max, 0);
but this would not work and would return NaN
. Here's the reason - acc
and item
are not the only arguments to the custom callback. When you call Math.max()
tries to call it on non-numeric arguments, resulting in NaN
.
Notice that I didn't put much thought into picking the initial value. I just picked it as 0
; resulting in a bug!
So, what if my Array is consisted of values less than zero? Say, arr = [-7, -56, -5, -2]
. The returned value would be 0
, which is not even present in the Array arr
.
Instead, we should pick the lowest possible value for initial value.
var arr = [-20, -50, -5, -60];
arr.reduce(function(acc, item){
return Math.max(acc, item);
}, -Infinity);
We are getting there. We should hone our skills on another Array related problem. Just to have some fun, let's go with a bit tougher one.
Say, we are to find LCM of an Array of integers. Now, from theory, we know that LCM of two numbers would be product of them, divided by their HCF.
Eucledian algorithm for HCF finding exists; and abundant are its implementation. No point wasting your time making you write an HCF function when you can write one yourself, or find one.
Rather, let's look at how to extend LCM of two numbers into LCM of multiple numbers. Newsflash - it's not product of entire array divided by their HCF. Nope. That would be mathematically wrong.
LCM of three numbers would be LCM of first two numbers; then LCM of the first LCM with the remaining number. Similarly, you can formulate a strategy to find out LCM of sub-array first, then take another number and find its LCM with the first LCM.
So, how do we formulate the solution? We need to think of acc
in the middle of an iteration. The final acc
should be the LCM of the entire array, no doubt. But during the nth
iteration also; acc
should hold the LCM of the (n-1)
elements traversed so far.
And yes, the initial value. It should be a number, whose LCM with another number would be the other number. Clearly, it is 1
.
Let's write our reduce
solution.
var arr = [1, 2, 3, 4, 5, 6];
arr.reduce(function(acc, item){
return acc * item / hcf(acc, item);
}, 1);
I am assuming an hcf()
function is available in the environment. I picked the entries in a way; it should return 60
as answer.
More Reduce
Reduce is not just a function to provide you with utilities to solve some Mathy problems like sum of the array, hcf of the array, minimum of the array etc.
It is perfectly capable of going above and beyond. We shall be dealing with some complex examples for now.
Say, you wish to flatten nested arrays. And yes, before you start jumping up-and-down in your seat - the nesting could be any arbitrary level deep.
For instance, we could take this Array to test our code with.
var arr = [[1, 2, 3], ['cat', 'dog', ['fish', 'bird'], [[[]]]]];
This looks sufficiently complex to begin with - nested arrays, empty nested arrays with varying depth.
The output should be [1, 2, 3, 'cat', 'dog', 'fish', 'bird']
It's time to formulate a strategy. We clearly need to distinguish between an array and an element. Also, acc
should be the array being formed throughout the iteration; meaning the initial value would be an empty array []
.
Throughout the callback function code, we would simply extract the content from the item
, which can be a deeply nested array; and we would Array.prototype.concat()
it with the acc
value. It's better to use concat()
over Array.prototype.push()
; because push()
alters the original array; while concat()
creates a new array and returns it.
And since we don't know the level of nesting at any given instant; we must go call our custom callback recursively. Meaning, we have to write it somewhere else and call it by name inside reduce()
.
var arr = [[1, 2, 3], ['cat', 'dog', ['fish', 'bird'], [[[]]]]];
function flattenArray(arr) {
return arr.reduce(function(acc, item){
if(Array.isArray(item)){
return item.reduce(flattenArray, acc);
}
return acc.concat(item); // this does the ordering. If you want reverse ordered output, just reverse it!
}, [])
}
// call it like this
flattenArray(arr);
Of course, this requires some background in recursive functions; but that's not too difficult to pick up, compared to the matter of this long one!
Yes, go ahead and play with it. But notice how we can simply write 3-4 lines of clean functions keeping a few simple guidelines in mind - and do something as complex as that reliably. This is readable and maintainable.
For instance, if you want to alter or tweak the logic the logic later (Say you want to upper case some string or encode some string); you can easily identify where to alter. The actual nesting happens inside the if
condition. And the way we have used the reduce
call there - it maintains the order of elements as they are in the array.
Let's take another seemingly complex example, and bring it to its knees weilding the sword of reduce
!
We are to find out the symmetrical differences of two or more arrays. It looks daunting; but then you start to think.
What would the initial value be? Of course, we are forming an array; so it would be an empty array []
to begin with. Then there's the acc
- since our final solution would contain a diff-ed array; it would have to be an array too. This would keep piling on the symmetric differences of the arrays encountered so far.
Just to be clear, this function could accept arbitrary number of arrays; so, we have to convert them all to an array of arrays for easy manipulation.
function symDiff(args){
// convert args to an Array
var argsArray = Array.prototype.slice.call(arguments);
// now do the reduce magic!
argsArray.reduce(function(acc, item){
return acc
.filter(function(itemInAcc){
return item.indexOf(itemInAcc) === -1;
})
.concat(item.filter(function(itemInItem){
return acc.indexOf(itemInItem) === -1;
}));
}. []);
}
Yes, I know. It looks big. So, let's see if we can refactor to make it small. Notice that both the filter
functions do same work; except with altered set of argument pairs. Cool! Let's create a separate function and call it twice with those arguments.
function symDiff(args){
// convert args to an Array
var argsArray = Array.prototype.slice.call(arguments);
// now do the reduce magic!
argsArray.reduce(function(acc, item){
var funWithFiltering = function(arr1, arr2){
return arr1.filter(function(itemInArr1){
return arr2.indexOf(itemInArr1) === -1;
});
};
return funWithFiltering(acc, item).concat(funWithFiltering(item, acc));
}. []);
}
This looks better. But there is still one other problem. This would keep duplicates in the array. If that is not needed, we could just as easily write another function using reduce
to remove the duplicates.
function removeDuplicates(arr){
arr.filter(item, index, self){
// Keep only the first instance of the array, as given by indexOf()
// Remove other elements from Array
return self.indexOf(item) === index;
}
}
We cannot keep on ignoring this any longer. I have been using filter
while promising to use reduce
, right? The reason is simple - filter
can be written with reduce
. In fact, any array operation, in theory; can be implemented with reduce()
.
Do give it a try! Implement map
and filter
with reduce
. You have to take care of optional arguments too.
Wrapping up
Whoa that was quite a lot! But I think I have made a strong case of using reduce
whenever you want to use a loop to get it done. Be habituated with it like its your first nature.
As soon as you get a problem on some String transformation or Array manipuation; start by writing
return arr.reduce(function(acc, item){_}, _);
And then fill in the blanks. When you are using reduce()
, you are thinking in terms of interaction of every element with another element. You are forming the output by acculumating it from start to finish.
The framework Redux embraces the reduce
principle and is gaining high popularity in web design.
Also notice another salient feature - reduce
forces or guides you to form your solution without altering anything existing. For instance, in the last example; we were filtering and concatenating - but we knew it would work as is; because the first set of operation did not change any of the acc
or item
within that iteration.
This would be a great time to level with you, that, the initialValue
parameter is optional. You don't need to provide it explicitly.
If you omit this; for the first iteration acc
would be the first item in the array, and item
would be the second item in the array. This would mean we can write a sum of array utility just omitting it. Or, we don't need to think of -Infinity
in case of finding maximum value in array - it would work just fine if we remove the initial value.
But in some complex situations, it would be better to visualize and formulate the solution in terms of some base - some initialization. However, if you are more comfortable without it, to each his own!
If you have any further questions or suggestions, come join our gitter chatroom; and tell us how you reduce
!
Learn to code and help nonprofits. Join our open source community in 15 seconds at http://freecodecamp.com
Follow our Medium blog
Follow Quincy on Quora
Follow us on Twitter
Like us on Facebook
And be sure to click the "Star" button in the upper right of this page.