Use Case
_.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
pick
to each level in an object. - If a property is an
object
/array
, then apply apick
. - Keep all
object
/array
only 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
_.pick
and_.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 = { a: 5, b: { a: 1}, c: { b: 3}};
pickDeep(testCase2, 'a'); // {a: 5, b: {a: 1}}
var testCase3 = { a: 5, b: [ { a: 1}, { c: 2}, {d: 3} ], c: [ {c: 2}, {d : 3}]}
pickDeep(testCase3, 'a'); //{ a: 5, b: [ {a: 1} ]}
var testCase4 = [ {a: 5}, {b: 2}, {c: {a :3 }}, {d: [ {a: 4}] }, z: [ { f: 34}] ];
pickDeep(testCase4, 'a'); // [ {a:5}, {c: {a:3}}, {d: [ {a:4}]}];
Execution Code
function isIn(collection) {
return function(value, key) {
return _.contains(collection, key);
}
}
console.log(pickDeep(data, isIn(['a', 'c'])));
_.pick
in logic that allows for a deep traverse, rather than re-implementing the pick functionality. \$\endgroup\$_.cloneDeep
and_.pick
together, but I haven't been able to connect the dots. \$\endgroup\$pick
always returns an object. But your test cases want it to return an array? Your code fails testCase4 due to that consideration \$\endgroup\$