3 ms·
The advice you quoted is the most valuable of all, in my opinion. You give "map/filter/reduce" as an example and claim that theses approaches "typically result
by jlg23 9y ago
The advice you quoted is the most valuable of all, in my opinion.
You give "map/filter/reduce" as an example and claim that theses approaches "typically result in passing over the data multiple times". No, since reduce can behave like map and filter, with a proper reduction function you only have to pass over the data once.
> Most collections/array I process have trivial number of elements (<100) and you get virtually no benefit from writing optimized code.
That is true for all other advice given in the original article, but not for this: A reduction function only needs one input element and the aggregate/result so far. This function then does not care whether it is called in the context of list or vector iteration, it will happily work with elements read from a stream or any other potentially destructive iterator. The benefit is obvious: Write & debug once, document and never touch the code again until the actual algorithm implemented there changes.
- lmm 9y ago> No, since reduce can behave like map and filter, with a proper reduction function you only have to pass over the data once. You can indeed - which is why reduce is relatively opaque and unmaintainable, and should be a last resort. Any given map/filter pipeline could be rewritten to reduce, and it quite possibly would perform better - but at the cost of not being able to test individual pipeline stages, nor inspect the intermediate results in a debugger. Most of the time that's a bad tradeoff.
- jlg23 9y agoI disagree. I does not have to be unmaintainable. The difference between chaining map/filter and a single reduce is mostly a syntax transformation plus a little bit of thinking upfront: ;; N.B.: Code was written here in a comment and never tested. ;; It might need some of those: ')))))' (flet ((filter-element (element bucket) ;; all (filter...)s of your chain here ) (mutate-element (element bucket) ;; apply all your (map...)s here )) (defun distill-magic (essence element) (if (not (filter-element element essence)) essence (cons (mutate-element element essence) essence)))) The hard part is sometimes to reformulate the chain in a way that you only filter on either pre- or post-mutation data. If you can't, your most probably using the wrong algorithm. But fixing that, if it requires serious thinking, is something I defer to the moment it actually matters. I now can, because it is neatly encapsulated in a single, local function definition. And yes, of course I can inspect intermediate results in a debugger: Just trace distill-magic or set a break point.