At Underscore Js, Can I Get Multiple Columns With Pluck Method After Input Where Method As Linq Select Projection
Solution 1:
To project to multiple properties, you need map
, not pluck:
var results = _.map(
_.where(people, {city : "ny"}),
function(person) {
return { firstName: person.firstName, qty: person.qty };
}
);
[{"firstName":"Thein","qty":5},{"firstName":"Michael","qty":3}]
Note that, if you wanted to, you could create a helper method "pluckMany" that does the same thing as pluck with variable arguments:
// first argument is the source array, followed by one or more property namesvar pluckMany = function() {
// get the property names to pluckvar source = arguments[0];
var propertiesToPluck = _.rest(arguments, 1);
return _.map(source, function(item) {
var obj = {};
_.each(propertiesToPluck, function(property) {
obj[property] = item[property];
});
return obj;
});
};
You can use the _.mixin
function to add a "pluckMany" function to the _
namespace. Using this you can write simply:
var results = _.chain(people).where({city : "ny"}).pluckMany( "firstName", "qty").value();
Solution 2:
TL;DR Use :
var results = _.chain(people)
.where({ city: "ny" })
.map(_.partialRight(_.pick, 'firstName', 'qty'))
.value();
But please read on for explanations as I feel the process of finding this solution is more interesting than the actual answer.
The general pattern would be (it works with lodash
too) :
_.map(array, function(obj) { return _.pick(obj, 'x', 'y', 'z'); });
Given this general map
function which transforms each element of a collection, there are multiple ways to adapt this to your particular situation (that vouch for the flexibility of map
, which is a very basic building block of functional programs).
Let me present below several ways to implement our solution :
var _ = require('lodash'); // @lodash 2.4.1 at the time of writing// use underscore if you want to, but please see http://stackoverflow.com/questions/13789618/differences-between-lodash-and-underscore/* la data */var people = [{
firstName: "Thein",
city: "ny",
qty: 5
}, {
firstName: "Michael",
city: "ny",
qty: 3
}, {
firstName: "Bloom",
city: "nj",
qty: 10
}];
/* OPTION1 : mixin' with _ */
_.mixin({
pluckMany: function() {
var array = arguments[0],
propertiesToPluck = _.rest(arguments, 1);
return _.map(array, function(item) {
/* Alternative implementation 1.1
* ------------------------------
* Taken from @mMcGarnagle answer
* _each is easy to understand here,
* but has to modify the variable `obj` from a closure
* I try to avoid that for trivial cases like this one.
*/var obj = {};
_.each(propertiesToPluck, function(property) {
obj[property] = item[property];
});
return obj;
/* Alternative implementation 1.2
* ------------------------------
* Rewrite the previous code,
* by passing the accumulator (previously`obj`, but really it is an object that accumulates the result being constructed) across function calls.
* This construction is typical of the `reduce` function, closer to a functionnal programming style.
*/return _.reduce(propertiesToPluck, function(obj, property) {
obj[property] = item[property];
return obj;
}, {});
/* Alternative implementation 1.3
* ------------------------------
* If we are already using lodash/underscore,
* then let's use the `pick` function ! I also included an example of `flatten` here
*/return _.pick(item, _.flatten(propertiesToPluck, true));
/* Alternative implementation 1.4
* ------------------------------
* But really flatten is not needed.
*/return _.partial(_.pick, item).apply(null, propertiesToPluck);
});
}
});
/* Let's use our mixed function !
* Since we call several _ functions on the same object
* it is more readable to chain the calls.
*/var results = _.chain(people)
.where({
city: "ny"
})
.pluckMany('firstName', 'qty')
.value();
/* OPTION 2 : without mixing our code with lodash/underscore */var results = _.chain(people)
.where({
city: "ny"
})
.map(_.partialRight(_.pick, 'firstName', 'qty'))
.value();
console.log(results);
If you like this way of writing code with underscore
or lodash
, I highly suggest that you have a look at functional programming, as this style of writing as well as many functions (map
, reduce
amongst many others) come from there.
Note : This is apparently a common question in underscore : https://github.com/jashkenas/underscore/issues/1104
This is apparently no accident if these are left out of underscore/lodash : "composability is better than features". You could also say do one thing and do it well
. This is also why _.mixin
exists.
Solution 3:
Yep, I wish pluck
had an option of passing an array, but in the meantime, you could do:
constpluckFields = (arr, fields) => _.map(arr, item => _.pick(item, fields))
Solution 4:
My understanding is the author of the question wants to take an array of objects with many properties and strip each object down to a small list of properties.
There are myriad ways of doing so with _ , but I like this way best. Pass in an empty result object which will be "this" inside the function. Iterate with _each , and _pick the fields you want:
var myObjects = [
{ "first" : "eric",
"last" : "gumbo",
"code" : "x482"
},
{ "first" : "john",
"last" : "dinkman",
"code" : "y9283"
}
];
var result = [];
_.each( myObjects, function(itm) { this.push(_.pick(itm,"first","code")) }, result );
console.log(result);
Solution 5:
YAAUu-Yep Another Answer Using underscore...
// use a proper browser to run this code snippet, a browser that is es6-compliantlet people = [{
firstName: "Thein",
city: "ny",
qty: 5
},
{
firstName: "Michael",
city: "ny",
qty: 3
},
{
firstName: "Bloom",
city: "nj",
qty: 10
}
];
// either you pick the properties you want let picking = _.iteratee((person) =>_(person).pick("firstName", "city"));
// either you omit the properties you do not wantlet omitting = _.iteratee((person) =>_(person).omit("qty"));
// create the filter by cityletliving = (people, city) => _(people).where({
"city": city
});
// put the "filter by city" into a mixin (as I assume it would be used again & again)
_.mixin({
living: living
});
// do the thing (twice), // these chaining methods could be done into a mixin as wellconsole.log("results by picking properties:", _(people).chain().living("ny").map(picking).value());
console.log("results by omitting properties:", _(people).chain().living("ny").map(omitting).value());
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Post a Comment for "At Underscore Js, Can I Get Multiple Columns With Pluck Method After Input Where Method As Linq Select Projection"