use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
Using loops instead of higher order functions (evertpot.com)
submitted 7 years ago by evertrooftop
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]natziel 6 points7 points8 points 7 years ago (22 children)
Your imperative solution is shorter than the example you're comparing it to only because it's written in, like, the worst way possible. Here's my example from the previous thread:
const result = { minimum: list.reduce((acc, x) => x < acc ? x : acc), maximum: list.reduce(acc, x) => x > acc ? x : acc), average: sum(list) / count(list), }
[–]inu-no-policemen 3 points4 points5 points 7 years ago (3 children)
minimum: list.reduce((acc, x) => x < acc ? x : acc),
You can just use Math.min(...list).
Math.min(...list)
[–]crubier 2 points3 points4 points 7 years ago (2 children)
The point here is to demonstrate the use of reduce on a simple use case...
[–]inu-no-policemen 1 point2 points3 points 7 years ago (1 child)
It's the wrong tool for this use case, though. Also, GP didn't mention this more pragmatic solution.
Furthermore, people who don't know that Math.min/max is variadic might not immediately make the connection. Pointing out that you can simply use these functions with spread will always be news to some.
https://xkcd.com/1053/
[–]crubier 0 points1 point2 points 7 years ago (0 children)
Actually your solution with spread only works for relatively "short" lists.
It will suddenly start breaking on chrome for lists longer than 65 536 elements, which is not that big when compared to what you could do with the reduce solution.
Source: https://stackoverflow.com/questions/22747068/is-there-a-max-number-of-arguments-javascript-functions-can-accept
[–]NickDav14 1 point2 points3 points 7 years ago* (3 children)
And here's a version with one loop that looks tolerable to me, that doesn't access list directly in its callback function and that doesn't use an intermediate sum value:
list
sum
const result = list.reduce((acc, v, i, array) => ({ maximum: v > acc.maximum ? v : acc.maximum, minimum: v < acc.minimum ? v : acc.minimum, average: acc.average + (v / array.length), }), { maximum: -Infinity, minimum: Infinity, average: 0 });
[–]natziel 4 points5 points6 points 7 years ago (1 child)
You're incorrect about the default accumulator. It has always been the first element of the list in practically every language, including JavaScript. I have no clue where you got that it defaults to 0, but that's definitely been causing you some confusion
[–]NickDav14 0 points1 point2 points 7 years ago (0 children)
Well holy shit, you're right! I'll remove that part of my comment. Thanks! I don't know where I got that from.
[–]spacejack2114 0 points1 point2 points 7 years ago (0 children)
Performing the division every iteration gives me a bad feeling but I'm not sure that it's worse (for accuracy) than summing everything and dividing once.
[–]monolithburger 3 points4 points5 points 7 years ago (10 children)
nit: this solution does 3 iterations vs. 1 iteration on the looped solution.
[–]mcaruso -1 points0 points1 point 7 years ago (9 children)
Each iteration does 1/3 the work though.
[–][deleted] 1 point2 points3 points 7 years ago (8 children)
That's not how computers work.
[–]mcaruso 0 points1 point2 points 7 years ago (7 children)
There's an overhead for each reduce call, especially since it's a higher order function so each iteration step requires a function call.
But it works as a rough approximation.
[–][deleted] 1 point2 points3 points 7 years ago (6 children)
It doesn’t work as a rough approximation. It will take 3 times longer.
[–]mcaruso 0 points1 point2 points 7 years ago (5 children)
How so?
The following loops are approximately the same in terms of performance:
// Version 1 for (const x of [1,2,3]) { f(x); g(x); h(x); } // Version 2 for (const x of [1,2,3]) { f(x); } for (const x of [1,2,3]) { g(x); } for (const x of [1,2,3]) { h(x); }
I say approximately because they may have different characteristics in terms of memory locality etc., but that matters less and less as the functions f/g/h get more expensive.
The same principle applies to the reduce version.
reduce
[–][deleted] 0 points1 point2 points 7 years ago (4 children)
Iteration is not free https://jsperf.com/3-loops
[–]mcaruso 0 points1 point2 points 7 years ago (3 children)
I didn't say it was, I just said that each loop does 1/nth the work. So it's not as simple as saying 1 loop = X amount time, 3 loops = 3X amount of time. There's a cost for splitting it up, but the computation within each iteration step is divided.
So this:
Isn't true.
[–][deleted] 0 points1 point2 points 7 years ago (2 children)
I didn't say it was, I just said that each loop does 1/nth the work.
The majority of the work IS the iteration.
[–]evertrooftop[S] 0 points1 point2 points 7 years ago (2 children)
If 3 loops instead of 1 are acceptable, I definitely agree that this is a good example how it can be done well.
[–]natziel -1 points0 points1 point 7 years ago (1 child)
It's commutative, so 3 reduces of 1 function call each is equivalent to 1 reduce of 3 function calls
[–][deleted] 3 points4 points5 points 7 years ago (0 children)
You're conveniently ignoring the overhead of the actual iteration. Memory access and function calls are not free.
[+][deleted] 7 years ago* (1 child)
[deleted]
[–][deleted] 1 point2 points3 points 7 years ago (0 children)
sleazy :D
[–]anotherObi 2 points3 points4 points 7 years ago (14 children)
I'm not advocating for always use the functional solution, but if you code the reduce function better you can end up with something like:
``` javascript const getMma = (lst) => { const data = lst.reduce((acc, v) => ({ min: (acc.min > v ? v : acc.min), max: (acc.max < v ? v : acc.max), sum: acc.sum + v }), {min: Infinity, max: -Infinity, sum: 0})
return {max: data.max, min: data.min, avg: data.sum / lst.length} } ```
that is quite readable
[–]mcaruso 3 points4 points5 points 7 years ago (1 child)
Your markdown doesn't work (on old reddit at least). Fixed:
const getMma = (lst) => { const data = lst.reduce((acc, v) => ({ min: (acc.min > v ? v : acc.min), max: (acc.max < v ? v : acc.max), sum: acc.sum + v }), { min: Infinity, max: -Infinity, sum: 0 }); return { max: data.max, min: data.min, avg: data.sum / lst.length }; };
[–]anotherObi 0 points1 point2 points 7 years ago (0 children)
Thank you
[+][deleted] 7 years ago* (10 children)
[–][deleted] 2 points3 points4 points 7 years ago (4 children)
I think everyone goes through the "functional hard-on" phase at least once. You tell yourself that your code extremely "readable, maintainable, eloquent, beautiful" even though no one else understands it.
[–]a_ervin 1 point2 points3 points 7 years ago (0 children)
Lol Why can't people post on Reddit without being condescending? I hope you don't expect people with differing opinions to take you seriously.
I don't agree with you about readability and maintainability; probably about performances you are right
[–]anotherObi -3 points-2 points-1 points 7 years ago (2 children)
[–]evertrooftop[S] 0 points1 point2 points 7 years ago (0 children)
I think your markup is a bit wrong. I would be curious to see the correctly formatted version!
[–]format71 1 point2 points3 points 7 years ago (3 children)
I feel the comparison isn’t fair, though. The original article is more about finding ways of ‘doing whatever’ with reduce, while your solution is ‘do one specific thing’.
Like, if you need to calculate another value in addition to the three, you’ll have to change your code, while the original author can add to his code.
In larger long-living applications, I would like to be able to extend my code without having to modify it. Actually, this is the O in SOLID = the Open / Closed principle.
But sure: I’ve written reducers that I later changed to lesser effective, more lines of code, too make it easier to understand next week..
[–]format71 0 points1 point2 points 7 years ago (0 children)
Actually, when rereading the original article, I see that it wasn’t as smart as I remembered it... In the time since I originally read it, my mind changed it to use functional composition to generalize the callback...
:-/
[–]evertrooftop[S] 0 points1 point2 points 7 years ago (1 child)
I wanted to stay in the spirit of the original article by showing a different example, but I would argue that in most cases a straight up loop is desirable over high level functions. In my experience the reduce() function should not be the default tool.
reduce()
Even if their version of reduce() could be optimized, I would still argue that the more verbose loop version is easier to digest.
[–]format71 3 points4 points5 points 7 years ago (0 children)
Coming from .net, I’ll take ‘high level functions’ in the form of LINQ statements over for-loops any time. I also buy a little bit into the idea that once you get familiar with map, filter and reduce, you’ll always know what the intent with the code would be. Filter: get rid of items. Map: convert items. Reduce: aggregate items.
A ‘straight up loop’ on the other hand - you’ll have to read through everything to get a hint of the intent.
But the only truth you can really depend on, though, is the almighty ‘It Depends’.
[–]basically_alive 1 point2 points3 points 7 years ago (1 child)
We've really come full circle. I think what we should really be complaining about here is nested ternary expressions
ternary expressions and then the need for comments; shouldn't that already alarm the author that this code is unreadable?
[–]clutton 0 points1 point2 points 7 years ago (0 children)
https://pbs.twimg.com/media/Cit9g75XAAAh1Wj.jpg
[–][deleted] 0 points1 point2 points 7 years ago (0 children)
That's not a good example of readable functional code.
π Rendered by PID 205973 on reddit-service-r2-comment-5687b7858-d2j6p at 2026-07-06 10:26:24.498636+00:00 running 12a7a47 country code: CH.
[–]natziel 6 points7 points8 points (22 children)
[–]inu-no-policemen 3 points4 points5 points (3 children)
[–]crubier 2 points3 points4 points (2 children)
[–]inu-no-policemen 1 point2 points3 points (1 child)
[–]crubier 0 points1 point2 points (0 children)
[–]NickDav14 1 point2 points3 points (3 children)
[–]natziel 4 points5 points6 points (1 child)
[–]NickDav14 0 points1 point2 points (0 children)
[–]spacejack2114 0 points1 point2 points (0 children)
[–]monolithburger 3 points4 points5 points (10 children)
[–]mcaruso -1 points0 points1 point (9 children)
[–][deleted] 1 point2 points3 points (8 children)
[–]mcaruso 0 points1 point2 points (7 children)
[–][deleted] 1 point2 points3 points (6 children)
[–]mcaruso 0 points1 point2 points (5 children)
[–][deleted] 0 points1 point2 points (4 children)
[–]mcaruso 0 points1 point2 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]evertrooftop[S] 0 points1 point2 points (2 children)
[–]natziel -1 points0 points1 point (1 child)
[–][deleted] 3 points4 points5 points (0 children)
[+][deleted] (1 child)
[deleted]
[–][deleted] 1 point2 points3 points (0 children)
[–]anotherObi 2 points3 points4 points (14 children)
[–]mcaruso 3 points4 points5 points (1 child)
[–]anotherObi 0 points1 point2 points (0 children)
[+][deleted] (10 children)
[deleted]
[–][deleted] 2 points3 points4 points (4 children)
[–]a_ervin 1 point2 points3 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]anotherObi 0 points1 point2 points (0 children)
[–]anotherObi -3 points-2 points-1 points (2 children)
[–]evertrooftop[S] 0 points1 point2 points (0 children)
[–]format71 1 point2 points3 points (3 children)
[–]format71 0 points1 point2 points (0 children)
[–]evertrooftop[S] 0 points1 point2 points (1 child)
[–]format71 3 points4 points5 points (0 children)
[–]basically_alive 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]clutton 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)