5 ms·
function splitLineReducer(acc, line) { return acc.concat(line.split(/,/g)); } const investigators = fileLines.reduce(splitLineReducer, []); That’s un
by minitech 7y ago
function splitLineReducer(acc, line) {
return acc.concat(line.split(/,/g));
}
const investigators = fileLines.reduce(splitLineReducer, []);
That’s unnecessarily quadratic. So yes, definitely use the more readable `flatMap` (with appropriate polyfill):
const investigators = fileLines.flatMap(line => line.split(','));
(The `flatMap` in the article is not an appropriate polyfill)
The object spread example has the same problem, like c-smile mentioned. Use a Map for lookups instead.
> Some readers might point out that we could get a performance gain by mutating the accumulator. That is, we could change the object, instead of using the spread operator to create a new object every time. I code it this way because I want to keep in the habit of avoiding mutation. If it proved to be an actual bottleneck in production code, then I would change it. ↩
Avoiding (very local) mutation because it’s an FP bad word in a language like JavaScript is just a terrible way to go about things. Also, this turns out to be an actual bottleneck way more often than people notice.
- saagarjha 7y agoIndeed, some languages (such as Swift) provide a mutating reduce because it makes sense to use it in some cases.
- nirvdrum 7y ago> Also, this turns out to be an actual bottleneck way more often than people notice. I wish more devs -- particularly web front-end devs -- tried out their work on something that isn't a top-of-the line developer computer. There are plenty of devices out there that are computationally constrained and/or memory-bounded. Moreover, no one ever runs these things in isolation. So, while profiling in isolation makes a ton of sense to rule out external factors, in the real world you're competing with all the other open tabs and windows. That's a tricky problem to model, of course, but it doesn't mean we shouldn't try.
- d0m 7y agodeploying the same javascript code on both web and old android devices (using RN) keeps you honest about performance :O
- tomxor 7y ago> I wish more devs -- particularly web front-end devs -- tried out their work on something that isn't a top-of-the line developer computer. I agree, and I am, and I do. I held out on laptop from 2009 until recently, it had a core 2 duo, It was (and is) a really good machine for showing up sloppy performance hungry websites, and has been the source of a few of my rants here on HN when discovering some stupid side JS animation saturating one of it's cores unnecessarily. I agree there's a lot of shitty JS code out there. But there are a few of us web devs that care, and will do anything we can to prevent the crap we see around us.
- pault 7y agoIt's best to test on an actual device, but chrome developer tools does have CPU and network throttling to simulate slower machines.
- jacobolus 7y ago> That’s unnecessarily quadratic. So yes, definitely use the more readable `flatMap` (with appropriate polyfill): > const investigators = fileLines.flatMap(line => line.split(',')); It’s often nice to use iterators, e.g. with pieces from https://observablehq.com/@jrus/itertools https://observablehq.com/@jrus/itertools const inspectors = Array.from(flatten(map(line => line.split(','), fileLines))) Then the steps can be broken down into smaller pieces if desired, without needing to re-store all of the content temporarily at every step along the way. Python’s generator expressions also often make this kind of thing even clearer: list(name for line in fileLines for name in line.split(',')) Ideally there would also be a nice iterator-producing “split” method/function for scanning through the string incrementally so that it would be unnecessary to construct a separate array for each split.
- minitech 7y agoHmm… not sure how that particular iterator version is an improvement. Aside: the Python inspectors = list(name for name in ','.split(line) for line in file_lines) is backwards in two ways and should be inspectors = [name for line in file_lines for name in line.split(',')]
- jacobolus 7y ago> not sure how that particular iterator version is an improvement In this case it is not. But if you want to do more complicated things, you can do several steps with iterators, and then crystallize an array (or sometimes a single reduced result) at the end. * * * Edit: whoops I had it correct it in my python shell and then mindlessly typed it wrong into this conversation. Apologies! * * * Also yes sure you should use a list comprehension at the end in the Python, but again if you use generator expressions you can keep working on them for several lines of streaming transformations without needing to actually construct any full list along the way. * * * As an example, instead of TFA’s min/max example, we can do something like: const readings = [0.3, 1.2, 3.4, 0.2, 3.2, 5.5, 0.4], [r0, r1] = tee(readings, 2), running_min = accumulate(r0, Math.min), running_max = accumulate(r1, Math.max), [rmin, rmax] = last(zip(running_min, running_max));
- dfee 7y agoThis is the first time I’ve ever seen an emoji (↩️) in a HN comment. I thought they were stripped? Interesting!
- bmn__ 7y agoThis technically isn't an emoticon. It's an Other_Symbol U+21A9 ‹↩› \N{LEFTWARDS ARROW WITH HOOK} followed by a Nonspacing_Mark U+FE0F ‹◌️› \N{VARIATION SELECTOR-16}. VS16 forces rendering of graphemes as a colourful graphic (where supported). https://en.wikipedia.org/wiki/Variation_Selectors_%28Unicode_block%29 https://en.wikipedia.org/wiki/Variation_Selectors_%28Unicode...
- cuddlecake 7y agoAvoiding local mutation in JS for the sake of avoiding it is especially bad because Functional Programming Languages with immutable data usually have optimizations for these kind of things. JavaScript does not.
- mehrdadn 7y ago> That’s unnecessarily quadratic. Any idea why concat() doesn't optimize it? Having a refcount of 1 should be enough information to make it linear, right? Or do the GC engines not keep track of refcounts at all?