Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the underscore.js equivalent to LINQ's SelectMany operator?

Imagine I have a nested array structure.

var nested = [ [1], [2], [3] ]; 

Using underscore.js, how would I produce a flattened array?

In C# you would use Enumerable.SelectMany like this:

var flattened = nested.SelectMany(item => item); 

Note that the lambda in this case selects the nested item directly, but it could have been any arbitrary expression.

In jQuery, it's possible to just use:

var flattened = $.map(nested, function(item) { return item; }); 

However this approach doesn't work with underscore's map function.

So how would I get the flattened array [1, 2, 3] using underscore.js?

like image 518
Drew Noakes Avatar asked Sep 10 '12 00:09

Drew Noakes


People also ask

What is function underscore JS?

Underscore. JS is a popular javascript based library which provides 100+ functions to facilitate web development. It provides helper functions like map, filter, invoke as well as function binding, javascript templating, deep equality checks, creating indexes and so on.


1 Answers

If you have a slightly more complicated array, say one coming from JSON, you can take advantage of the pluck method as well, extracting the specific property you are interested in, similar to parents.SelectMany(parent => parent.Items);

// underscore version var allitems = _.flatten(_.pluck(parents, 'items')); 

allitems is now the array of all subitems from the parents, [a,b,c,d].

And a JSFiddle showing the same thing.


Or, if you are using lodash you can do the same thing by using the _.flatMap function which is available since version 4. Cred to Noel for pointing it out in the comments.

var parents = [    { name: 'hello', items: ['a', 'b'] },    { name: 'world', items: ['c', 'd'] }  ];      // version 1 of lodash, straight up  var allitems = _.flatMap(parents, 'items');  logIt('straight', allitems);    // or by wrapping the collection first  var allitems = _(parents)    .flatMap('items')    .value();  logIt('wrapped', allitems);    // this basically does _(parents).map('items').flatten().value();    function logIt(wat, value) {    console.log(wat, value)  }
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>  <pre id="result"></pre>

In case you want to do more stuff and don't want to chain operators, you can use the flow function to get the same effect. This is useful if you are using TypeScript and importing each operator individually, since you can then optimize your final payload.

const parents = [    { name: 'hello', items: ['a', 'b'] },    { name: 'world', items: ['c', 'd'] }  ];  logIt('original', parents);    const result = _.flow(    (collection) => _.flatMap(collection, (item) => item.items),    (flattened) => flattened.filter((item) => item !== 'd')  )(parents);  logIt('result without "d"', result);    function logIt(wat, value) {    console.log(wat, value);  }
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>  <pre id="result"></pre>
like image 66
Patrick Avatar answered Oct 05 '22 06:10

Patrick