loading...

Which Array Function When?

andrew565 profile image Andrew Steele ・3 min read

There's a lot of hullaballoo some days about "you should use reduce more" or "you don't need a filter, use a map", or "For? Why not forEach?"

The truth is, Arrays and all of their iterator functions can be confusing for beginners, so I'm going to try and simplify things for everyone by framing the question from the end: what do you want to get back?

Short version

  • Return one thing for each existing thing: map()
  • Return only some of the existing things: filter()
  • Return only one new thing: reduce()
  • Don't return anything, but do something with each existing thing: forEach()

I'll give you a quick rundown of each, followed by examples using the older, non-arrow-function syntax as well as the newer arrow-function syntax.

Return one new entry for every existing entry: map()

If you have an array of values, and you want to do something to each entry in that array and return a new array with the new values, then map() is your friend. Here's a simple function that takes an array and doubles every entry:

const originalArray = [1, 2, 3];
const newArray = originalArray.map(function(item) {
  return item * 2;
});
console.log(newArray); // -> [2, 4, 6]

Here's the same thing using the newer syntax:

const originalArray = [1, 2, 3];
const newArray = originalArray.map(item => item * 2);
console.log(newArray); // -> [2, 4, 6]

Notice that, with the newer arrow syntax, we don't have to use the function keyword, the return keyword, or curly brackets. That's because arrow functions give us an implicit return for 'simple' functions like this one. You can read more about arrow functions here, from Wes Bos.

Return a new array with only some of the existing entries: filter()

Filter is probably the easiest array function to understand, because it is so well-named. Filter takes an array of values, performs a function or comparison on each value, and then returns a new array of just the values that pass it's test (what we call 'truthy' values).

Here's an example that takes an array of numbers and returns just the ones that are larger than 5:

const originalArray = [1, 9, 4, 2, 42];
const newArray = originalArray.filter(function(item) {
  return item > 5;
});
console.log(newArray); // -> [9, 42]

Here's the filter part with an arrow function:

const newArray = originalArray.filter(item => item > 5);

Return one new thing only: reduce()

Sometimes you have an array of values and just want to return one new thing from them. Reduce takes an array, performs a function or comparison on each item, and then does something to what's called an 'accumulator'. This is one of those functions that's actually easier to describe with an example, because the terms one has to use to describe it are just as confusing as the function itself!

Suppose you have an array of names, and you want to count the number of times the name 'Bob' shows up:

const originalArray = ["Alice", "Bob", "Charlie", "Bob", "Bob", "Charlie"];
const numberOfBobs = originalArray.reduce(function(accumulator, item) {
  if (item === "Bob") {
    return accumulator + 1;
  } else {
    return accumulator;
  }
}, 0);
console.log(numberOfBobs); // -> 3

Again with arrows:

const numberOfBobs = originalArray.reduce((accumulator, item) => {
  if (item === "Bob") {
    return accumulator + 1;
  } else {
    return accumulator;
  }
}, 0);

As you can see, the arrow function didn't save us as much typing this time, because we had to provide two parameters to the function and then had logic before we could return, so we still needed curly brackets.

The 0 at the end of the reduce function is the value we start off the accumulator with, adding 1 to it if the value we encounter is "Bob", otherwise we return the accumulator as it currently is. If you don't return anything, then the next time the function is run the accumulator will be undefined.

Do something with each array value but don't return anything: forEach()

Sometimes you'll have an array of values that you want to do something with, but don't need to keep track of what the return is from each function call. This is what forEach() is for.

const originalArray = [1, 2, 3];
originalArray.forEach(function(item) {
  doSomething(item);
});

And again with arrows:

originalArray.forEach( item => doSomething(item); );

Final Notes

Simple and sweet. These are the simplest use cases I could come up with for each function to try and make it as easy as possible to understand when you should use each. There is a huge amount of tasks you can do with these functions, and there is an 'advanced' form of each of these functions that gives you the current index too:

arr.map((item, index) => {})
arr.filter((item, index) => {})
arr.reduce((accumulator, item, index) => {})
arr.forEach((item, index) => {})

If you need it, use it!

Posted on by:

andrew565 profile

Andrew Steele

@andrew565

Dreamer, husband, father, developer, writer. I like to code in the front end, and I like helping people learn how to develop more easily.

Discussion

markdown guide
 

Nice!! Also, reduce can be much simpler:

const originalArray = ["Alice", "Bob", "Charlie", "Bob", "Bob", "Charlie"];

const numberOfBobs = originalArray.reduce((accumulator, item) => {
   return (item === "Bob" && accumulator + 1) || accumulator;
}, 0);

console.log(numberOfBobs);
 

I'll just briefly explain what that && does, for everyone not understanding what you mean:

&& returns the value of the right-hand expression when both are truthy.

Same with ||: It returns the left-hand expression if it's truthy, or the right-hand one of the first one was falsey.

See the descriptions of the logical operators (and the examples) on MDN for more information.

So && can be used like 'when the left expression is truthy, return the right-hand (or run a function)'.

E.g.

condition && doThis()

And || can be used to provide a default value (or also run a function or something).

someVariable = someVariable || 0
someVariable || varIsFalsey()

Hope this was not too confusing.

 

While using && to actually return the latter is indeed a cool trick, it's probably confusing for beginners. And in my opinion the ternary operator comes in more handy in this case.

Here's a simple approach which uses the ternary operator and should also be pretty easy to understand for beginners:

const originalArray = ['Alice', 'Bob', 'Charlie', 'Bob', 'Bob', 'Charlie']

const numberOfBobs = originalArray.reduce(
  (acc, item) => item === "Bob" ? acc + 1 : acc,
  0
)

That works, because

if (item === 'Bob') {
  return acc + 1
} else {
  return acc
}

is basically the same as

return item === 'Bob' ? acc + 1 : acc

(Think of ? and : as 'then' and 'else')

And since we can leave away the curly braces in this case (since it's just one expression), we can simply use this arrow function:

(acc, item) => item === 'Bob' ? acc + 1 : acc

So this was a brief explanation (hopefully someone understands what I'm saying) of the ternary operator, see MDN to learn more

 

If i would ever seen such code i would instantly decline any pull request this may be contained in.
Do you seriously mean that it make it simpler in any way? I have been programing node.js apps for a 3 years now and seen some horrible things done in sake of simplicity and performance and this may be one of those. What if acumulator have started as -1 for some reason? You would have never change it in the end.

 

I understand how the ternary and the logical operators work, and still I agree with you that it doesn't make it "simpler". If and else takes some more lines of code, but it's more easy to debug, refactor, document compared to single line expressions.

 

You are right, when accumulator stars in -1, it'll fail. When I said much simpler, I meant simpler in terms of writing code. :D

 

Has no one mentioned filter!?

const originalArray = ["Alice", "Bob", "Charlie", "Bob", "Bob", "Charlie"];
const numberOfBobs = originalArray.filter(name => name === "Bob").length;
console.log(numberOfBobs); // -> 3

I think a better example of reduce would be something that can't be done with filter.

 

return accumulator + Number(item === "Bob");

 

return (accumulator += (item === "Bob" ?1:0));

this way(using "?:" or "&&||" after equal sign) works better in lots of situation

 

That = in += is redundant since the reducer only needs to return the new value, not change the old one. I mean, it'll still work, because the correct value is returned, but there's no need in changing the passed-in accumulator.

 

Glad it's been helpful for so many folks already!

Yes, some of these functions could be reduced (pun intended) to an even smaller and possibly more performant size using &&, ternary operators, or ++accumulator instead of accumulator + 1. If you're interested in how to take your code to the next level with some of those refactors, definitely read the other comments here!

I intentionally stayed away from some of those 'intermediate level' code 'tricks' for the sake of making these examples as readable as possible. ;)

 

Nice article! Everyone seems to forget my two favorite functions though, some and every

If you've ever written something like

const items= [1, 9, 4, 2, 42];

// checks if any item in the array matches the predicate
var hasAnyBigItems = items.some(item => item > 10));

// checks if every item in the array matches the predicate
var allPositive = items.every(item => item > 0);

If you ever find yourself checking the length property after items.filter(), you can likely use some or every to do the same thing without the array generation penalty.

 

Really nice!!! I'm a Python programmer and didn't know JS has functions like that!! Congrats bro

 

Best explanation of reduce I've found to date. awesome!

 

Do you know if forEach is better in term of perf than for ?

Nice post !

 

According to this for is pretty much always faster than forEach, so if performance is more important than concise code (and it usually should be) a for loop is likely a better choice.

 

Correct, as the forEach call will incur a penalty invoking the lambda expression. forEach could have equivalent performance if the JIT inlines the lamba method body, but it's safe to say always expect forEach to be a bit slower.

 

I always try to understand the contents of Multivitamins and Supplements been sold in the market before making best choice of what to go for.

 

Great article. Reduce is indeed hard to grasp at first. I took very long to learn to use it and now I can't live without it :)

It's also worth noting that these functions become more powerful when you chain them as needed, without declaring new variables just to hold a result and improving readability of code. But chain responsibly, you can also make a mess out of it.

 

If only I would have read this article back then!

I struggled my way to learn about these type of higher order functions with .NET's LINQ and Kotlin's standard library.

But this post is gold. I'll make sure to share it with friends.

 

Great article dude. Well written and easy to understand. You might want to reference at least once the arrow functions real name is a Lambada function. Can't wait to read more

 

Thanks Peter. I believe you're referencing lambda expressions, which are expressions which return a function. While it's true that Javascript arrow functions are comprised of a syntax which enable shorter definitions of expressions which return functions, very very few people in the Javascript community refer to these as lambda expressions. Doing so promotes confusion for newer developers more than helping them, as searching for 'Javascript lambda functions' just redirects them back to 'arrow functions'. The official standard also calls them arrow functions, so that's what I went with here.

 

Thanks for the reply. And the spelling correction 😣 I should have used a real keyboard and not my thumbs. That's good to know that they're officially called arrow functions, I will make note of that for myself. Thanks again,
Pete

 

Ya, this one is hot: originalArray.forEach( item => doSomething(item); );

 

Zamob.co.za is one of the largest mobile web portal in South Africa, where mobile users can download lots of android games, videos, mp3 music and java games all for free. You can download millions of free Games, Apps, Music....

 

Thanks! I didn't know about reduce. I prefer to use the most simple and readable for the occasion and the most necessary

 

Why forEach, what about for...of and for...in ?

 

I included forEach here because this article was specifically about the iterator functions built into the Array object. for...of and for...in are super great tools, too, but were out of scope for this article. Will definitely include in the larger piece I'm working on writing. ;)

 

This is great! As a beginner I am always confused between the Filter/Map/Reduce, it is super helpful to have this! Thank you

 

Well arrow functions still save us some code in case reduce.

const numberOfBobs = originalArray.reduce((accumulator, item) => (
  item === 'Bob' ? accumulator + 1 : accumulator
);
 
 

This breakdown of array functions, was exactly what I was looking for. Thanks for taking the time to explain them!

 

Great tutorial!! Got god understand about array stuff!

 

This is some of the clearest JavaScript writing I've seen.

 
[deleted]
 

Thanks for your thoughts Rafael. This article is aimed at beginners, so I chose the easiest-to-read, more verbose way of expressing things.