-
-
Save vvgomes/451ea5ca2c65e87c92e4 to your computer and use it in GitHub Desktop.
var _ = require("lodash"); | |
var R = require("ramda"); | |
var companies = [ | |
{ name: "tw", since: 1993 }, | |
{ name: "pucrs", since: 1930 }, | |
{ name: "tw br", since: 2009 } | |
]; | |
var r1 = _(companies).chain() | |
.filter(function(c) { | |
return c.name.split(" ")[0] === "tw"; | |
}) | |
.map(function(c) { | |
return { | |
name: c.name.toUpperCase(), | |
since: c.since | |
}; | |
}) | |
.sortBy(function(c) { | |
return c.since; | |
}) | |
.reverse() | |
.value(); | |
console.log("with lodash:", r1); | |
var r2 = R.compose( | |
R.reverse, | |
R.sortBy(R.prop("since")), | |
R.map(R.over(R.lensProp("name"), R.toUpper)), | |
R.filter(R.where({ name: R.test(/^tw/) })) | |
)(companies); | |
console.log("with ramda:", r2); |
Ramda seems to be better in terms of speed:
https://jsperf.com/ramda-vs-lodash
https://jsperf.com/ramda-vs-lodash/3
However, both are extremely sluggish as compared to native imperative code. Hopefully that will change in the future
lodash.fp and more es6
var r5 = _.flow(
_.filter(o => o.name.startsWith('tw')),
_.map(o => ({ ...o, name: o.name.toUpperCase() })),
_.sortByOrder('since', 'desc')
)(companies);
A shorter Ramda version:
var r3 = R.pipe(
R.filter(R.pipe(R.prop('name'), R.startsWith('tw'))),
R.map(R.over(R.lensProp('name'), R.toUpper)),
R.sort(R.descend(R.prop('since'))),
)(companies)
With Ramda compose, we seem have to reverse the order? Does it make the function group even harder to read?
You can use Ramda pipe
instead of compose
.
Thanks for the battle this is pretty interesting (and entertaining haha!)
And if we strip @a-x- version of unnecessary underscores… ;-)
var r5 = companies
.filter(c => c.name.startsWith("tw"))
.map(c => ({ ...c, name: c.name.toUpperCase() }))
.sort((a, b) => b.since - a.since);
Someone would have to try extra hard to convince me that 9 function invocations of 9 different Ramda methods (all of which you along with all present and future team members have to have memorised) is better in any aspect…
@kamiltrebunia what if companies
or c.name
is null or undefined? ;) lodash
and ramda
handles that for you
@hillerstorm yep, and the first function can easily be a filter or reducer to eliminate invalid entities
@hillerstorm: Got you covered!
var r5 = (companies || [])
.filter(c => c.name && c.name.startsWith("tw"))
.map(c => ({ ...c, name: c.name.toUpperCase() }))
.sort((a, b) => b.since - a.since);
Even though Ramda is definitely more powerful, and I do prefer Ramda over lodash, I've found that for a lot of common operations lodash is simpler to use. It handles many real world cases that Ramda doesn't. For instance, when you iterate object properties with lodash it will skip "hidden" properties (that start with _
) by default. It also performs much better on some operations, of course it doesn't really matter most of the time.
An even shorter Ramda version:
const r3 = R.pipe(
R.filter(R.where({ name: R.startsWith('tw') })),
R.map(R.evolve({ name: R.toUpper })),
R.sort(R.descend(R.prop('since')))
)
r3(companies)
in the lodash example you said c.name.split(" ")[0] === "tw"
but in the ramda's one you've put a regex R.test(/^tw/)
. Really?
The same regex could be also applied in the first case, natively /^tw/.test(name)
which is actually shorter.
But that would not be point-free. The point is not being shorter. The point is being point-free, auto-curried, composable.
Thanks for adding to the discussion :)
Oh, I wasn't aware of this comparison.
how about from performance perspective? anyone has done it?
This all seems cool but in the end what is the performance difference. I mean when you end up working on the project where half of devs love Ramda and the other half worship Lodash the only reasonable argument is performance.
I heard that Lodash team has done some insane tricks to optimize the performance including using while loops instead of native to make iterators fast.
Has anyone done comprehensive benchmarking?