patternjavascriptModerate
Deep pick using lodash/underscore
Viewed 0 times
underscorelodashdeepusingpick
Problem
Use Case
Requirements
Improvements
I'd like any constructive criticism to improve this code, but I'm mainly interested in advice pertaining to:
Function
(jsfiddle)
Test Data
Test Cases
```
var testCase1 = { a: 5, b: 6};
pickDeep(testCase1, 'a'); // {a : 5}
var testCase2
_.pick creates a shallow clone of an object given a predicate that identifies which keys to keep. pickDeep would perform a deep clone of the object and would "pick" up all nested objects containing the given keys. All containers containing the nested objects would remain and would not be removed.Requirements
- Recursively apply a
pickto each level in an object.
- If a property is an
object/array, then apply apick.
- Keep all
object/arrayonly if the descendant properties fulfill thepick.
Improvements
I'd like any constructive criticism to improve this code, but I'm mainly interested in advice pertaining to:
- Readability
- Flexibility
- Performance
- Implementing this with
_.pickand_.cloneDeep
Function
(jsfiddle)
function pickDeep(collection, identity, thisArg) {
var picked = _.pick(collection, identity, thisArg);
var collections = _.pick(collection, _.isObject, thisArg);
_.each(collections, function(item, key, collection) {
var object;
if (_.isArray(item)) {
object = _.reduce(item, function(result, value) {
var picked = pickDeep(value, identity, thisArg);
if (!_.isEmpty(picked)) {
result.push(picked);
}
return result;
}, []);
} else {
object = pickDeep(item, identity, thisArg);
}
if (!_.isEmpty(object)) {
picked[key] = object;
}
});
return picked;
}Test Data
var data = {
a: 5,
b: 6,
c: 7,
d: {
a: 65,
z: 6,
d: {
a: 65,
k: 5
}
},
e: [
{a : 5},
{b : 6},
{c : 7}
],
f: [
{
b : [ { a: 5, z: 5 } ],
c : 6
},
{
g: 0
}
]
};Test Cases
```
var testCase1 = { a: 5, b: 6};
pickDeep(testCase1, 'a'); // {a : 5}
var testCase2
Solution
Here's the most elegant way I can think of writing this. I use
These changes also allow you to use more than 2 pick properties (
For
This also fixes a the need to check
transform to handle both Arrays and Objects as your tests showed you wanted to support them, though as pointed out in comments your code didn't.These changes also allow you to use more than 2 pick properties (
pickDeep(set, 'a', 'b', 'c', ['d', 'e'])) as you can with the normal pick/omit.For
lodash 3 and underscore 1.8? you'll need to change _.createCallback to _.iteratee the rest of the code should remain the same.function pickDeep(collection, predicate, thisArg) {
if (_.isFunction(predicate)) {
predicate = _.createCallback(predicate, thisArg);
} else {
var keys = _.flatten(_.rest(arguments));
predicate = function(val, key) {
return _.contains(keys, key);
}
}
return _.transform(collection, function(memo, val, key) {
var include = predicate(val, key);
if (!include && _.isObject(val)) {
val = pickDeep(val, predicate);
include = !_.isEmpty(val);
}
if (include) {
_.isArray(collection) ? memo.push(val) : memo[key] = val;
}
});
}This also fixes a the need to check
pickDeep({a: [{a: 1}]}) twice to add it to the picked objectCode Snippets
function pickDeep(collection, predicate, thisArg) {
if (_.isFunction(predicate)) {
predicate = _.createCallback(predicate, thisArg);
} else {
var keys = _.flatten(_.rest(arguments));
predicate = function(val, key) {
return _.contains(keys, key);
}
}
return _.transform(collection, function(memo, val, key) {
var include = predicate(val, key);
if (!include && _.isObject(val)) {
val = pickDeep(val, predicate);
include = !_.isEmpty(val);
}
if (include) {
_.isArray(collection) ? memo.push(val) : memo[key] = val;
}
});
}Context
StackExchange Code Review Q#57976, answer score: 15
Revisions (0)
No revisions yet.