1

I read on some forums that lodash chain should be avoided when possible for better performances and readability of code. So is there a way to use native javascript functions on collection to replace this code.

_(userCollection).chain()
        .map('name')
        .compact()
        .uniq()
        .value();

Something like this bellow, but I' not sure that it gives any added value to write it like so

_.uniq(_.compact(userCollection.map('name')))
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
kyserslick
  • 591
  • 1
  • 10
  • 27
  • 1
    **[Izaak Schroeder's article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba)** making this point is a good read. The short answer is to switch to lodash/fp, and use constructs like `flow`/`flowRight` instead of the chain. – Scott Sauyet Apr 12 '18 at 14:28
  • 1
    It's a wonderful article but I'm unclear about the OP's statement "I read on some forums that lodash chain should be avoided when possible for better performances and readability of code." and it's relation to that article. The article talks about "how to get a 2x build-time performance increase and 1.5x bundle size decrease" which is not a "run time performance increase". The article also discusses why/how `.chain` promotes readability, which is why people use it. – gforce301 Apr 12 '18 at 14:43
  • @gforce301: The main point of the article is to show problems with `chain` and to promote an alternative that is at least as readable, perhaps more so: `flow`. That's the same style promoted by Ramda (of which I'm an author) and which is common in functional languages. – Scott Sauyet Apr 13 '18 at 12:54

2 Answers2

6

You can use _.flow() to run a sequence of methods:

const { flow, partialRight: pr, map, compact, uniq } = _;

const getUniqeNames = flow(
  pr(map, 'name'),
  compact,
  uniq
);

const arr = [{ name: 'John' }, {}, { name: 'Smith' }, {}, { name: 'John' }, { name: 'Smith' }] 

const result = getUniqeNames(arr);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Flow works better with lodash/fp, since the methods are iteratee-first and data-last. This saves the need to partial right every method that requires an argument (pr(map, 'name') in the lodash example).

const { flow, map, compact, uniq } = _;

const getUniqeNames = flow(
  map('name'),
  compact,
  uniq
);

const arr = [{ name: 'John' }, {}, { name: 'Smith' }, {}, { name: 'John' }, { name: 'Smith' }] 

const result = getUniqeNames(arr);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
2

I believe this is what you're looking for. No lodash needed.

lodash.map can be changed to Array.prototype.map

lodash.compact can be changed to Array.prototype.filter

lodash.uniq can be changed to a Set constructor and optionally be converted to an Array again.

const users = [
  {name: 'Me'},
  {name: 'Someone Else'},
  {name: 'Someone Else'},
  {name: ''},
];

const uniqueNames = Array.from(new Set(users
  .map(user => user.name)
  .filter(name => name)));

console.log(uniqueNames);
Remco Haszing
  • 7,178
  • 4
  • 40
  • 83
  • 1
    `.filter(Boolean)` might be cleaner than `.filter(name => name)`. – Scott Sauyet Apr 12 '18 at 14:31
  • The answer could provide benchmarks for completeness, since the question addresses performance. Generally I'd expect Lodash to be more performant. – Estus Flask Apr 12 '18 at 14:33
  • It's not clear to me whether the question is about that specific code or the technique. This is fine for the specific code, but there are plenty of lodash functions that have no simple native counterpart. – Scott Sauyet Apr 12 '18 at 14:36
  • 2
    @estus: Most of what I've seen in opposition to `chain` for performance reasons has been about bundle size, not execution speed. – Scott Sauyet Apr 12 '18 at 14:42
  • @ScottSauyet it's a general question with an example code. But I believe that talking performance, it's only meaningfull for front-end, for back-end everything is built – kyserslick Apr 13 '18 at 12:46
  • @kyserslick: The point I was making was that the `flow` technique is more general. You can include any function that fits your pipeline, not just those lodash ones specifically made ready for `chain`. I have no knowledge of the relative execution times of these two techniques, but the article mentioned above speaks to the difference in bundle size. – Scott Sauyet Apr 13 '18 at 13:00