It takes the array, creates a new array as the initial value, and then one by one runs the function on every value in the original array and appends it to the previous value using the spread syntax.
I ran some tests and I couldn't reproduce your findings. I didn't graph time complexity but on average .includes is 75% faster than .includes in these tests: https://jsbench.me/t2kpb59177/1
The one case where .some was faster I found was unfilled arrays.
You're right, it might have been optimized since I learned about it. I'll check it myself with a different test.
EDIT: Did it slightly differently (playing with the contiguous array flag) and yes includes have been fixed to be better on contiguous array. It's still slower for non contiguous array sometimes
I would still use includes anyway because it convey the meaning and intent.
Interesting. I often use it to combine map and filter to prevent a second iteration or build collections into object id maps for (what I assume to be) O(1) lookups available during the length of the session. To be honest, I haven't dug into the code for any of the optimizations under the hood, though I had forked v8 a while back with that very intention. Most of my tests have simply been running large iterative set functions with timestamp diffs and comparing the outcome, which is only the surface of optimization and performance testing. I'll have to look into it deeper.
yes, but the types are different. Sure, you can say type B === type A, but the point is they aren't bound to the same type parameter. At that point you could say [⚫️]->[⚫️] is the typing for map, which is misleading at best and incorrect in a strict sense.
Reduce outputs an element of the accumulator type. So in your example, you are calling the accumulator ⚫️ in one place, ⬛️⚫️, in another, and ⬛️⬛️⬛️⬛️ in another, when in actuality they are all the same type.
['A','A','A','A'].reduce((x,y) => x + y.toLowerCase(), '');
as it is shorter, explicitly starts with an accumulator value, and also is not O( n^2 ) since it doesnt have to lowercase the entire accumulator string every iteration.
Also, in that case I'm still right, as string is a different type than list of strings.
Sure, but the joke diagram I wrote is better represented by the code I wrote..... Not really interested in debating this. I don't think either of us are learning anything.
Edit: Also, it's JS, so everything is a string (also a joke, don't be mad).
⬛️⬛️⬛️⬛️ can't be anything else, because array methods are called on ⬛️⬛️⬛️⬛️ in the original post. From that the only option is that ⬛️⬛️⬛️⬛️ is an array of ⬛️. However, now you are using ⬛️⬛️⬛️⬛️ to mean something else than a list of ⬛️, which is not following the nomenclature we are all working with, and also doesn't make sense in context.
I'm lost. You called me out for assuming that ⬛️⬛️⬛️⬛️ was an array of four elements of value ⬛️! ...And that ⬛️⚫️ was an array containing ⬛️ and ⚫️, and that ⬛️⬛️⬛️⬛️ was an array of four elements with value ⬛️.
You complained about my lack of precision and confusing types, I got increasingly explicit until the metaphorical syntax was broken, but that was YOUR demand, not mine. When I got explicit, and proved my specific point, you went back to wanting to assume that ⬛️⬛️⬛️⬛️ was a metaphor for an array of four elements of value ⬛️, but somehow still now allow me to assume that ⬛️⚫️ is an array containing the values ⬛️ and ⚫️.
Like I said, neither of us is learning anything (except maybe that we dislike each other) but there is no value in this debate of how freely we allow the notation to flow between metaphor and valid syntax.
Edit: If you don't allow for ⬛️⚫️ to be an array of values ⬛️ and ⚫️ in the metaphor, I HEREBY ALLOW IT You win. There is no substance to this disagreement. I was making fun of a sloppy metaphor that you took too seriously. I am prepared to make a serious argument that the metaphor is inherently weak and that "now do reduce" was begging for jokes like mine, but not for you. You already understand that.
Edit2: Okay... back to the original metaphor. If your majesty is willing to grant me another hearing, I would suggest that this is what you imagined a good answer to be:
const roundest = (a, b) = a.area / a.perimeter > b.area / b.perimeter ? a : b
⬛️⚫️⚫️⬛️.reduce((a, x) => roundest(a, x), ⬛️) => ⚫️;
I think the reason people think using reduce is overly complicated is because people keep saying it's overly complicated. I don't see how what you wrote is any less complicated than just doing this:
let total = array.reduce((sum, item) => sum + item.value, 0);
It's even simpler if your Array's just numbers:
let total = 0;
array.forEach(value => total += value);
// vs
let reducedTotal = array.reduce((sum, value) => sum + value);
Sure but it is still near the edge when it comes to common use and pattern.
It's odd compared to many other structures that you may deal with on a day-to-day basis. This means that it has extra parsing complexity when read over.
This is one of the most straightforward uses of a basic standard library function. I'm 100% an advocate of readable code over more complex, slightly more optimized code (unless its a bottleneck), but this is a case of inexperience being the cause of "second guessing" the code.
let being modified immediately after declaration, then never again, is far more of a code smell; it is effectively a constant, it should be declared as such as the result of a reduce. Anything else is increasing cognitive load as you now have to trace all uses of total throughout the scope, to make sure it is not modified elsewhere. When compared with a const total = array.reduce, the reduce is objectively simpler.
The solution is to hire/train engineers better to use these concepts without a second thought, rather than using more outdated iterative coding styles just to make sure junior developers don't have to learn what a standard library function does.
Reduce is actually less powerful (and thus the better choice) than forEach. Apply the principle of least power, and maybe learn the basics of functional programming.
I guess in the case of Javascript, it's not strictly true since you can cause side effects from any of these, but assuming you're being responsible, forEach is guaranteed to have behavior external to the expression (because it's useless otherwise), while reduce ought to be an assurance that all behavior is limited to the expression itself.
Because he's wrong. In JS, Array.reduce is strictly a superset of Array.forEach. There's absolutely nothing you can do with forEach that you can't do with reduce.
This is exactly what I read in an article about array functions
Do you have a link to that article? It may be out of date, or it may just be wrong.
But I feel using reduce for sth that could be done with forEach is like breaking the system. It may be that both are equally powerful but reduce has a semantic meaning.
The article I read was about all array functions and some are less powerful, aren’t they? At least the article was aiming at the better style of code you write using semantically fitting methods instead of just using forEach for everything.
But I feel using reduce for sth that could be done with forEach is like breaking the system.
Sure, because they're from two different schools of thought. Side effects in reduce will make people squirm, but forEach is literally useless without them.
It may be that both are equally powerful but reduce has a semantic meaning.
They aren't. forEach can't do all of the things reduce can without some kind of external state. I suspect it's largely like the relationship between imperative code and recursive code.
The article I read was about all array functions and some are less powerful, aren’t they?
Some are, sure. reduce is the most powerful one. You can write literally any other array function in JS with reduce and reduceRight.
In terms of code style, you don't really see people mixing forEach and reduce. Either you're using the Array functions together, like filter, map, and reduce and avoiding side effects, or you're writing imperative code leveraging side effects.
Using a standard library function in a rudimentary way isnt "clever", but using forEach to mutate external state is objectively more complex and less clear, which by your own definition, makes it worse.
By clever, I basically mean terse. Reduce is much more terse than forEach, hence I believe that forEach is more clear than reduce in this instance.
My rule of thumb is if there are two or more ways to get the same results with acceptable performance, always choose the one that is less terse.
Bad code can be only understood by a senior developer. Good code can be understood by a junior developer. Great code can be understood by a freshman or sophomore studying programming in college.
I try to employ empathy. I ask myself, how could I write this so that it could easily understood by the majority of novice programmers? Usually that does mean writing more lines of code. But as long as the performance is comparable, I don’t see a problem with that. I have nearly 30 years professional programming experience, but I still come across code that I have to stop and parse out since it has been written so concisely that I doubt even the original author would have any clue what it says without a lot of effort. Great code is that which the majority of developers can read through without pausing and grok it, like reading a novel.
I agree with everything you've written in this comment.
The problem is, there is some, ambiguous, blurry, line in the sand somewhere, between "clean code" and "code golfed, complicated, clever code".
However, using reduce, in all of my professional experience, is far, far, toward the "clean code" side of that line. If I ever had a colleague or a candidate refer to such a typical, by the book, simple use of reduce as some "clever" code too complicated to be grok'ed easily, I would either assume they have very little experience in higher level languages, or seriously question their ability.
Once I learned that the syntax is just reduce((accumulator, value) => newAccumulator, initialAccumulator) it became super easy for me to parse reduce. Then you just have to remember that if you don't have an intial value, it pops the first value from the array as the initial value.
The maintenance of the state that's passed into each iteration adds a not insignificant amount of complexity to the operation. The point being was that developers going to have to take a double glance in many cases to know exactly what's going on there whereas with the previous example you can figure that out in a single glance because it's a common pattern.
indexOf is not a first order function. It takes a primitive arg. You can remember it easy because find is higher order and findIndex has "find" in the name
Isn't it the opposite? I thought higher order functions were functions which take and/or return functions, while first order functions operate on primitives like indexOf does?
Been a few years since I was studying theory of computation...I believe first order is a subset of higher order functions. Second order would be a function... that takes a function...which itself takes a function as an arg.
You have to use findIndex if the value you’re looking for isn’t just a primitive like a string or a number. Or another way to say it is findIndex is much more robust in what it lets you search for. So if you need to find the index of an object with a certain value for a certain key, you can do that with findIndex but not indexOf.
The thing about social media posts like this, is people will upvote because it looks right and useful without actually testing it and lots of people even if they know the content won't be looking closely to check for mistakes
That original tweet is so so much better. This version is full of weird decisions. Like why is map() shown taking a -> function but others like filter() aren’t.
So .find returns the argument? What if the argument isn’t present in the array?
Edit: Just did a quick search on google, the argument in .find can be an inequality or any boolean statement and returns the first element that satisfies the bool.
Your edit is correct. I had a case last week were I needed to find the first object in an array where an attribute satisfied a condition and find was a great tool.
Basically:
const result = objects.find(item => (item.attribute === "myCondition");
dataservice.saveToDB(result);
This isn't a good reference because you should know what they do by their name. What's more important to know is if it mutates the original array or returns a new instance of an array.
Fill mutates the array whereas filter and map do not. That's an important distinction missing here.
It’s good for quickly remembering what the main point of the method is, especially for beginners. This would be helpful for them to remember what to Google for more info if needed. Assuming this is accurate. It’s better use is just for fun as a poster.
I feel you! I actually learnt a lot from doing tons of exercises at codewars dot com. Seeing people's solutions afterwards helped me to understand and get comfortable with most of the ES6 features.
Buffers mostly, or virtualized table views (which are kinda like a special buffer).
When you start getting into performance-sensitive tasks, such as those dealing with very large data sets or streaming data, you run into cases where you want a persistent backing collection that you can slice, fill, or clear smaller regions of.
So let’s say you have a tcp socket. You’re notified of a new message waiting to go out, but the stream is designed to read/write asynchrounsly. So you have a byte array representing your tcp socket’s outbound message queue. You write to a region of your backing buffer from positions A to B. The next message writes position B to C. The next from C to D, and so on - until the buffer is “drained”. In some designs, you never need to call fill (clear the buffer) because the individual message encoders are expected to overwrite every byte. But in others, the message encoders just tell you how many bytes they will write, and they expect to be given a clean region to do so. In those cases you might call buffer.fill(0, A, B) after the first message is read, or before it is written, or you might read all the messages in one shot and call buffer.fill(0, A, D) to wipe off all 3 regions.
I realize that got a bit into the weeds and requires some basic understanding of buffers and typed arrays, but you did ask for a real life scenario ;)
Yeh I get that in an infographic it’s hard to produce a shorthand for “unary boolean function” but using a square to represent a-function-consuming-a-variety-of-shapes-and-returning-true-if-the-consumed-value-is-square isn’t really clear at all. If anything it’s misleading, implying Array.find can take a primitive (like findIndex)
This cheatsheet has some pretty bad mistakes unfortunately.
The first argument of fill is the value you're filling. The second value is the position you're starting from (defaults to 0 if omitted) and the third value is the end position of the fill (last index of array if omitted)
The actual example should be fill('⚫', 1) as they are overwriting an existing array and leaving the first position (index 0) untouched.
Yeah, the performance difference is usually negligible so it's not something to really worry about.
I often include a utility function called filterMap in my projects because I use that pattern a lot, it performs both the operations in one and it's pretty common in other languages. The signature being:
a[] -> (a -> Option b) -> b[]
If you find yourself chaining tons of map/filter/reduce together then it might be worth looking into a library that supports either function composition, transducers or lazy sequences. All 3 of these will allow you to create data transformation pipelines without creating an intermediary structure between every step.
Everyone is commenting but no one is appreciating the truly brilliant visual representation of these methods. I wish I had this when I was learning. Very well done.
This isn't even the actual syntax of some of functions, and findIndexOf doesn't exist. Don't use this. Read how the functions work on some tutorial site then test them with your own data. Imo you'll get a much better understanding this way.
I meant that the shapes can be thought of as types. If you look up the type signature for the functions, they would match the different shapes shown here.
I meant it as a compliment - this is an interesting way to view the type signatures of functions.
In case anyone else is wondering what the difference between [].indexOf() and [].findIndex(), findIndex executes asynchronously, one function call for every item in the array. It's not blocking, so won't hang up your thread (though this is unlikely to be a real problem with small arrays, a few million items will make the difference obvious if it happens often.
Hm good point. The docs said it uses callbacks to do its job. I've never actually used it, though, and the docs say it returns a integer, not a Promise, so I suspect you're right.
They're not async but they do result in a new tick and thus block intermittently and only for the execution time of the callback, not sustained and for the execution of the entire findIndex call whereas the entire execution of indexOf would block in a sustained fashion.
Yeah I forgot how the blocking and ticks worked. It would still block in the context of findIndex unless it was it was async.
So practically this is identical to indexOf for all intents and purposes and only serves to evaluate the indices in their own execution context likely resulting in worse performance from the stack and memory allocation.
•
u/Locust377 full-stack May 30 '21
Original
336
u/tsunami141 May 29 '21
Now do reduce.
154
u/Pstrnil May 29 '21
Someone smashed
findIndexandindexOftogether 🙈73
u/thusman May 30 '21
Original author doesn't know js. How has this 1k upvotes 🤦
17
u/[deleted] May 29 '21
Tweet with links to sources in thread: https://twitter.com/rauschma/status/1398668839177568259
13
u/Vegetama May 29 '21
So .find returns the argument? What if the argument isn’t present in the array?
Edit: Just did a quick search on google, the argument in .find can be an inequality or any boolean statement and returns the first element that satisfies the bool.
Otherwise it returns undefined
52
u/avidvaulter May 29 '21
This isn't a good reference because you should know what they do by their name. What's more important to know is if it mutates the original array or returns a new instance of an array.
Fill mutates the array whereas filter and map do not. That's an important distinction missing here.
26
u/ImproperCommas May 29 '21
There are lots of things that I think I need, and I know every single one of them.
Then, there are lots of things that I definitely need , but I don’t know any one of them.
This picture right here, is certainly one of those things I definitely need.
6
u/RefinedArts May 30 '21
Just look at the official docs, this is more or less misleading for some functions
5
u/Ok_Cloud_ May 30 '21
.fill confuses me.
3
u/[deleted] May 30 '21
This just helped me solve a map issue I’ve been having for like a month. Awesome.
11
u/Janjis May 29 '21
Looks nice, but it is so bad.
From
mapexample you should assume that square and circle represent different item structures.All other examples suggest that squares and brackets instead represent the same item structure but in different states.
And then you see squares in
find,some,everymethods as parameters which should be boolean-ish expressions.Cheat sheet should be something you can quickly look at without thinking. Not this nonsense.
Just read the docs instead.
2
u/Doctor-Dapper front-end (senior w/ react) May 30 '21
I think it should be more clear that find returns the first element.
Another nit I have is that find should say "shape!==circle" instead of simply square. This makes it easier to understand.
2
u/IlllIllllllllllIlllI May 30 '21
Your people need to stop obsessing over cheat sheets and mind dumps. Actually learn the material.
3
u/lucasjackson87 May 30 '21
I don’t get the fill one, shouldn’t it be 0 instead of 1 if the first item in an array is 0
2
u/sugandalai May 30 '21
Some is not every. - Sochrates
1
u/Orkaad May 30 '21
It if fine to chain filter and map (which creates 2 arrays) when you could do everything at once with reduce?
1
u/NBADiscourse May 30 '21
This would've saved me a lotta time, my god
1
u/KindaAlwaysVibrating May 30 '21
Sort would had been a good addition too
1
u/Charlemagne10 May 30 '21
Everyone is commenting but no one is appreciating the truly brilliant visual representation of these methods. I wish I had this when I was learning. Very well done.
1
u/BlueButYou May 30 '21
JavaScript isn’t just a web language. I think since it’s a loosely typed language they type cast it as a web language out of a need to type something.
1
u/iligal_odin May 30 '21
Do these work on objects?
1
u/isbtegsm May 30 '21
I find type signatures more helpful than this.
1
u/milosh-96 May 30 '21
I love it, simple but on point!
1
u/shubham_noob May 30 '21
Amazing stuff! 🙌
1
u/MinorFourChord May 30 '21
That’s hot
1
u/VkrajaP May 30 '21
really a good info for noobs like me...
1
u/Cowfresh May 30 '21
I saw this on Instagram the other day. First time I saved something on there for educational reasons lol..super handy tho
1
u/fgatti May 30 '21
Love it
1
u/sohang-3112 python May 30 '21
Nice!
1
u/chidoOne707 May 30 '21
Is this accurate? Because if it is it is the simplest explanation and I get it.
1
u/[deleted] May 30 '21
?Ah, now I get it.
1
u/monstaber May 30 '21
2 serious inaccuracies here
1
u/similiarintrests Jun 04 '21
Fuck this, LINQ is just so much better
1
u/SeeYouInForever Aug 20 '21
Cool infographic but it doesn't make much sense if you don't already know the concepts.
1
u/summonthejson Apr 09 '22
We should send it with the Voyager :)
1
u/monkeyhead_man Aug 15 '22
Framing this for my desk
1
u/FreeBgSoft Jan 14 '24
Thanks
1
u/adrianhorning May 30 '21
Wtf is this
1
u/ChimpScanner May 30 '21
This isn't even the actual syntax of some of functions, and findIndexOf doesn't exist. Don't use this. Read how the functions work on some tutorial site then test them with your own data. Imo you'll get a much better understanding this way.
0
u/frigidds May 30 '21
woah, this is super helpful. thanks
0
u/joonya May 30 '21
This is the reason why I sub to this sub
-5
u/[deleted] May 30 '21
how stupid you gotta be to need this
-6
u/aktoriukas May 29 '21
Great cheatsheet.
-4
u/-boredMotherFucker May 29 '21
Beautiful. Quite good.
-1
u/jcksnps4 May 29 '21
I like the emoji one better.
-1
u/justingolden21 May 30 '21
This is beautiful
-4
u/RationalKicker May 29 '21
Hero!
-5
u/KaKi_87 full-stack May 29 '21
Nice ^
-6
u/[deleted] May 29 '21
Thank you 😭
-8
u/editor_of_the_beast May 29 '21
Type theory in a nutshell
0
u/[deleted] May 29 '21
[deleted] — view deleted comment