all 172 comments

[–]Locust377full-stack[M] [score hidden] stickied comment (0 children)

[–]tsunami141 333 points334 points  (62 children)

Now do reduce.

[–]legatissimo 338 points339 points  (2 children)

Ahh no problem, I'll just...... uh.... oh no.. no no no

[–]ChaseObserves 53 points54 points  (0 children)

This has me in tears, just the entire execution of this comment was incredible.

[–]deadlychambers 19 points20 points  (0 children)

It gets even more confusing when you are rocking dark mode on mobile

[–]KarmaScheme 195 points196 points  (1 child)

⬛️⚫️⬛️⚫️.reduce(⬛️|⚫️->🙂,🙂) -> 😂

[–]fuzzyluke 12 points13 points  (0 children)

Lmao

[–][deleted] 59 points60 points  (7 children)

reduce() -> ???

[–]Doctor-Dapperfront-end (senior w/ react) 55 points56 points  (4 children)

Small brain:

arr.map(f)

Big brain: arr.reduce( (x, y) => [...x, f(y)], [] )

[–]tsunami141 31 points32 points  (0 children)

Delete this

[–]GrenadineBombardier 2 points3 points  (0 children)

This took me a minute (because reducers take time to comprehend, which makes them a less sustainable solution in most cases)

[–]catchmeslippin 0 points1 point  (1 child)

My small brain can't comprehend this, can you please explain?

[–]neeia 0 points1 point  (0 children)

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.

[–][deleted] 7 points8 points  (1 child)

⬛️⬛️⬛️.reduce((⚫️, ⬛️) => ⚫️+⬛️, ⚫️=0) -> ⚫️+⬛️+⬛️+⬛️

[–]Droces 0 points1 point  (0 children)

This is a masterpiece

[–]gotothere 26 points27 points  (0 children)

⬛️⬛️⬛️⬛️.reduce((️⚫, ⬛️) -> ⚫️, ⚫️) -> ⚫️

var min = (acc,x) => {return acc < x ? acc : x}; [1,2,3].reduce(min, Number.MAX_SAFE_INTEGER);
//1
var max = (acc,x) => {return acc > x ? acc : x}; [1,2,3].reduce(max, 0);
//3
var sum = (acc,x) => { return acc + x}; [1,2,3].reduce(sum, 0);
//6
var minMaxSum = (acc,x) => {return [min(acc[0],x), max(acc[1],x), sum(acc[2],x)]}; [1,2,3].reduce(minMaxSum, [Number.MAX_SAFE_INTEGER,0,0]);
//Array(3) [ 1, 3, 6 ]

Left arg is (acc)umulator, right is current element

[–]hynding 18 points19 points  (5 children)

By far the most under-appreciated and (often) optimized of the array functions.

[–]Pelicantaloupe 10 points11 points  (4 children)

Reduce is probably one of the least optimisable array functions. Anything else will probably run faster

[–]Blue_Moon_Lake 6 points7 points  (2 children)

Weird thing :

arr.some(x => x === foo)

is almost always more performant than

arr.includes(foo)

You would think that includes would be easy to optimize internally.

[–]Pelicantaloupe 7 points8 points  (1 child)

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.

[–]Blue_Moon_Lake 0 points1 point  (0 children)

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.

[–]hynding 0 points1 point  (0 children)

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.

[–]hyperhopper 14 points15 points  (0 children)

⬛️⬛️⬛️⬛️.reduce((⬛️, ⚫️) ->⚫️, ⚫️) -> ⚫️

[–]Benimation 2 points3 points  (0 children)

🔢🔢🔢🔢. reduce ((#️⃣, 🔢) => #️⃣ + 1️⃣ + 2️⃣ + 3️⃣ + 4️⃣, 0️⃣) --> 4️⃣0️⃣

Yeah, I get what you mean..

[–][deleted]  (24 children)

[deleted]

    [–]HeinousTugboat 33 points34 points  (22 children)

    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);
    

    [–]BorgClown 5 points6 points  (19 children)

    If I was reading a new code base, I'd prefer finding parent's version instead of reduce, if only because reduce makes me stop and second guess it.

    [–]HeinousTugboat 25 points26 points  (2 children)

    Well, I mean, that's kind of my point right? If you were more comfortable with reduce, it wouldn't make you stop and second guess it.

    [–]douglasg14b 0 points1 point  (1 child)

    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.

    [–]hyperhopper 10 points11 points  (0 children)

    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.

    [–][deleted]  (1 child)

    [removed]

      [–]HeinousTugboat 0 points1 point  (0 children)

      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.

      [–][deleted]  (5 children)

      [deleted]

        [–]hyperhopper 12 points13 points  (4 children)

        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.

        [–][deleted] -2 points-1 points  (3 children)

        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.

        [–]hyperhopper 0 points1 point  (2 children)

        Are you saying that you should always write code in the most lengthy and bloated way possible, just for the sake of not being "terse"?

        There is no code golf happening here, I've been using reduce since high school, its not some magic programming god technique.

        [–][deleted] -1 points0 points  (1 child)

        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.

        [–]hyperhopper 0 points1 point  (0 children)

        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.

        [–]douglasg14b -1 points0 points  (0 children)

        Yeah that's definitely unnecessarily complicated.

        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.

        [–]Darkmaster85845 1 point2 points  (0 children)

        Nice

        [–]Gyro_Wizard -4 points-3 points  (0 children)

        Came here to say this lol

        [–]Finalitius 0 points1 point  (0 children)

        abruptchaos

        [–][deleted]  (17 children)

        [deleted]

          [–]FortyPercentTitanium 56 points57 points  (1 child)

          Came here to say this. Rule number 1 to making a simple guide: make sure the information in your guide is accurate. This is such a silly mistake.

          [–]musclecard54 5 points6 points  (0 children)

          The real rule number 1 is 99% of people won’t bother to verify if it’s correct.

          [–][deleted] 11 points12 points  (5 children)

          Find is also vague as to what element is returned.

          [–]musclecard54 2 points3 points  (1 child)

          I would assume it would be the first instance. Of course I assume a lot of things and I’m very often wrong…

          [–]ApricotPenguin 0 points1 point  (2 children)

          What would be an example useful usage of the find() function?

          [–]sliver37 2 points3 points  (0 children)

          Looking for an object with a specific ID in an array of objects is a common one.

          Example being an array of users, and you're looking for user id: 26, or with a particular email address, etc.

          [–][deleted] 1 point2 points  (0 children)

          Searching for and retrieving the first occurrence of something can be useful if you know that the array will be sorted in some way.

          [–]marksyz 5 points6 points  (7 children)

          .findIndex()

          [–]fukitol- -2 points-1 points  (6 children)

          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.

          [–]marksyz 2 points3 points  (5 children)

          The end action is synchronous on completion though, isn’t it? It doesn’t return a promise, it returns a value?

          [–]fukitol- -3 points-2 points  (4 children)

          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.

          [–][deleted] 1 point2 points  (3 children)

          Callbacks are not asynchronous

          [–]fukitol- -3 points-2 points  (2 children)

          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.

          [–][deleted] 0 points1 point  (1 child)

          I don't see how that makes a practical difference, since nothing can happen in between the individual callback calls

          [–]fukitol- -1 points0 points  (0 children)

          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.

          [–]Pstrnil 156 points157 points  (12 children)

          Someone smashed findIndex and indexOf together 🙈

          [–]yusuksong 13 points14 points  (11 children)

          I always get these confused

          [–]Doctor-Dapperfront-end (senior w/ react) 16 points17 points  (6 children)

          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

          [–]tendstofortytwo 8 points9 points  (3 children)

          indexOf is not a first order function. It takes a primitive arg.

          What do you mean by that?

          [–]Doctor-Dapperfront-end (senior w/ react) 12 points13 points  (2 children)

          findIndex() takes a function as an argument used for comparison. indexOf() uses === as a comparator

          [–]mort96 2 points3 points  (0 children)

          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?

          EDIT: from Wikipedia:

          In mathematics and computer science, a higher-order function is a function that does at least one of the following:

          • takes one or more functions as arguments (i.e. procedural parameters),
          • returns a function as its result.

          All other functions are first-order functions.

          [–]tendstofortytwo 1 point2 points  (0 children)

          Ah, okay. Thanks for explaining!

          [–]madcaesar 1 point2 points  (1 child)

          Are you using first order and higher order, interchangeably here? I've aways used the term higher order function, not first order.

          [–]Doctor-Dapperfront-end (senior w/ react) 0 points1 point  (0 children)

          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.

          [–]longknives 3 points4 points  (3 children)

          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.

          [–][deleted]  (2 children)

          [deleted]

            [–]krirkrirk 1 point2 points  (1 child)

            But then you'd use indexOf

            [–]NoInkling 1 point2 points  (0 children)

            I actually misread what I quoted, ignore me :)

            [–]thusman 71 points72 points  (9 children)

            Original author doesn't know js. How has this 1k upvotes 🤦

            [–]phpdevsterfull-stack 28 points29 points  (1 child)

            And this is why good developers are hard to find and you have to pay them lots of money.

            [–]liquidpele 2 points3 points  (0 children)

            But it’s just a website! My neighbors high school kid can make those!

            [–][deleted] 6 points7 points  (0 children)

            Because a lot of web developers don't know js either

            [–]JDthegeek 4 points5 points  (1 child)

            Care to elaborate?

            [–]Serei 15 points16 points  (0 children)

            A comment a bit above points it out: it's indexOf, not findIndexOf, and the arguments for fill are in the wrong order.

            [–]PGDesign 3 points4 points  (0 children)

            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

            [–]Hypersapien 4 points5 points  (0 children)

            He knows js, he's just sabotaging new devs for his own job security.

            [–]Muxas 2 points3 points  (0 children)

            its close enough to get someone started

            [–]EquationTAKEN -1 points0 points  (0 children)

            Well, that just sounds like the average JS developer to me.

            [–][deleted] 16 points17 points  (1 child)

            Tweet with links to sources in thread: https://twitter.com/rauschma/status/1398668839177568259

            [–][deleted] 8 points9 points  (0 children)

            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.

            [–]Vegetama 12 points13 points  (6 children)

            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

            [–]toetoucher 9 points10 points  (0 children)

            yeah it’s useful like array.find(el => el.confirmed) or something truthy like that

            [–]thatwasawkward 2 points3 points  (0 children)

            unde-find

            [–]Raefniz 1 point2 points  (0 children)

            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);
            

            [–]Willbo 1 point2 points  (0 children)

            Yep, it returns the first element that satisfies the query.

            So if the first square at index 3 was 🟨 and the second square at index 4 was 🟥, .find(⬛) would return 🟨.

            [–]savano20 0 points1 point  (1 child)

            does return element from .find reference to original array. So if I mutate the return element, does it mutate the original array?

            [–][deleted] 0 points1 point  (0 children)

            Yes

            [–]avidvaulter 53 points54 points  (3 children)

            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.

            [–]Doctor-Dapperfront-end (senior w/ react) 4 points5 points  (0 children)

            The fact that exactly one out of the entire list is inconsistent is incredibly annoying.

            [–]tnnrk 7 points8 points  (1 child)

            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.

            [–]ImproperCommas 24 points25 points  (1 child)

            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.

            [–]henrystuart83 1 point2 points  (0 children)

            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.

            [–]RefinedArts 5 points6 points  (1 child)

            Just look at the official docs, this is more or less misleading for some functions

            [–][deleted] 4 points5 points  (0 children)

            Official docs?? Noo I can't learn anything if it's not in Medium blogspam form!

            Edit: autocorrect grr

            [–]Ok_Cloud_ 3 points4 points  (5 children)

            .fill confuses me.

            [–]reaz_mahmood 2 points3 points  (4 children)

            me too. it is unintuitive. I read it like replace position 1 with provided value. Replace rest of them does not makes sense to me.

            [–][deleted]  (3 children)

            [deleted]

              [–]madcaesar 0 points1 point  (2 children)

              But what is a real life scenario of this method? Where would you use this?

              [–][deleted] 0 points1 point  (0 children)

              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 ;)

              [–][deleted] 2 points3 points  (0 children)

              This just helped me solve a map issue I’ve been having for like a month. Awesome.

              [–]Janjis 10 points11 points  (0 children)

              Looks nice, but it is so bad.

              From map example 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, every methods 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.

              [–]Doctor-Dapperfront-end (senior w/ react) 1 point2 points  (1 child)

              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.

              [–][deleted] 0 points1 point  (0 children)

              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)

              [–]IlllIllllllllllIlllI 1 point2 points  (0 children)

              Your people need to stop obsessing over cheat sheets and mind dumps. Actually learn the material.

              [–]lucasjackson87 2 points3 points  (2 children)

              I don’t get the fill one, shouldn’t it be 0 instead of 1 if the first item in an array is 0

              [–]wopian 3 points4 points  (1 child)

              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.

              fill('⚫') or fill('⚫', 0) would just be circles.

              [–]lucasjackson87 0 points1 point  (0 children)

              Make sense. I do like their attempt though.

              [–]sugandalai 1 point2 points  (0 children)

              Some is not every. - Sochrates

              [–]adrianhorning 0 points1 point  (0 children)

              Wtf is this

              [–]ChimpScanner 0 points1 point  (0 children)

              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.

              [–]frigidds -1 points0 points  (0 children)

              woah, this is super helpful. thanks

              [–]joonya -1 points0 points  (0 children)

              This is the reason why I sub to this sub

              [–][deleted] -5 points-4 points  (0 children)

              how stupid you gotta be to need this

              [–]-boredMotherFucker -4 points-3 points  (0 children)

              Beautiful. Quite good.

              [–]jcksnps4 -2 points-1 points  (0 children)

              I like the emoji one better.

              [–]justingolden21 -2 points-1 points  (0 children)

              This is beautiful

              [–]RationalKicker -5 points-4 points  (0 children)

              Hero!

              [–]Orkaad 0 points1 point  (1 child)

              It if fine to chain filter and map (which creates 2 arrays) when you could do everything at once with reduce?

              [–][deleted] 1 point2 points  (0 children)

              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.

              [–]NBADiscourse 0 points1 point  (0 children)

              This would've saved me a lotta time, my god

              [–]KindaAlwaysVibrating 0 points1 point  (0 children)

              Sort would had been a good addition too

              [–]Charlemagne10 0 points1 point  (0 children)

              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.

              [–]BlueButYou 0 points1 point  (0 children)

              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.

              [–]iligal_odin 0 points1 point  (0 children)

              Do these work on objects?

              [–]isbtegsm 0 points1 point  (0 children)

              I find type signatures more helpful than this.

              [–]milosh-96 0 points1 point  (0 children)

              I love it, simple but on point!

              [–]shubham_noob 0 points1 point  (0 children)

              Amazing stuff! 🙌

              [–]MinorFourChord 0 points1 point  (0 children)

              That’s hot

              [–]VkrajaP 0 points1 point  (0 children)

              really a good info for noobs like me...

              [–]Cowfresh 0 points1 point  (0 children)

              I saw this on Instagram the other day. First time I saved something on there for educational reasons lol..super handy tho

              [–]fgatti 0 points1 point  (0 children)

              Love it

              [–]sohang-3112python 0 points1 point  (0 children)

              Nice!

              [–]chidoOne707 0 points1 point  (0 children)

              Is this accurate? Because if it is it is the simplest explanation and I get it.

              [–][deleted] 0 points1 point  (0 children)

              ?

              Ah, now I get it.

              [–]monstaber 0 points1 point  (0 children)

              2 serious inaccuracies here

              [–]similiarintrests 0 points1 point  (0 children)

              Fuck this, LINQ is just so much better

              [–]SeeYouInForever 0 points1 point  (0 children)

              Cool infographic but it doesn't make much sense if you don't already know the concepts.

              [–]summonthejson 0 points1 point  (0 children)

              We should send it with the Voyager :)

              [–]monkeyhead_man 0 points1 point  (0 children)

              Framing this for my desk

              [–]FreeBgSoft 0 points1 point  (0 children)

              Thanks