Skip to content

Instantly share code, notes, and snippets.

@lamchau
Last active February 25, 2016 15:43
Show Gist options
  • Save lamchau/6bdec31090061c1e2293 to your computer and use it in GitHub Desktop.
Save lamchau/6bdec31090061c1e2293 to your computer and use it in GitHub Desktop.
mixin for underscore/lodash to deeply extract values with a given key/predicate
// deep _.pluck/_.map combined with a _.compact
_.mixin({
extract: function(object, predicate, values) {
values = _.isArray(values) ? values : [];
_.each(object, function(value, key, hash) {
if (_.isObject(value)) {
_.extract(hash[key], predicate, values);
}
var isString = _.isString(predicate) && key === predicate;
var isFunction = _.isFunction(predicate) && predicate.call(null, value, key);
if (isString || isFunction) {
values.push(value);
}
});
return values;
}
});
// _.pluck/_.map but takes the root values
// [ { x: 10, y: 10 },
// { x: 1, y: 2 },
// { x: 2, y: 2 },
// { x: 3, y: 0 },
// { x: 0, y: 3 },
// { x: 1, y: 1 } ]
var v = _.extract({
coordinates: { x: 10, y: 10 },
playerA: { coordinates: { x: 1, y: 2 }},
playerB: { coordinates: { x: 2, y: 2 }},
playerC: { coordinates: { x: 3, y: 0 }},
playerD: { coordinates: { x: 0, y: 3 }},
playerE: { coordinates: { x: 1, y: 1 }},
}, 'coordinates');
// [ Math.PI, Math.LN10 ]
_.chain({
a1: { value: Math.PI },
a2: { next: { value: Math.E } },
a3: { next: { next: { value: Math.LN10 } } }
})
.extract(function(value, key) { return /^(a1|a3)$/.test(key); })
.extract('value')
.value();
// [ 'hi', 'hello', 'world', 'foo' ]
_.extract({
name: 'hi',
a: {
name: 'hello'
},
b: {
other: {
name: 'world'
},
name: 'foo'
}
}, 'name')
test("_.extract", assert => {
let actual = _.extract({
coordinates: { x: 10, y: 10 },
playerA: { coordinates: { x: 1, y: 2 }},
playerB: { coordinates: { x: 2, y: 2 }},
playerC: { coordinates: { x: 3, y: 0 }},
playerD: { coordinates: { x: 0, y: 3 }},
playerE: { coordinates: { x: 1, y: 1 }},
}, "coordinates");
let expected = [
{ x: 10, y: 10 },
{ x: 1, y: 2 },
{ x: 2, y: 2 },
{ x: 3, y: 0 },
{ x: 0, y: 3 },
{ x: 1, y: 1 }
];
assert.deepEqual(actual, expected, "should extract all the values (root + children)");
actual = _.extract({
"value": 1,
"right": {
"value": 3,
"left": {
"value": 6,
"left": {
"value": 8
},
"right": {
"value": 9
}
}
},
"left": {
"value": 2,
"left": {
"value": 4,
"left": {
"value": 7
}
},
"right": {
"value": 5
}
}
}, "value");
expected = [1, 3, 6, 8, 9, 2, 4, 7, 5];
assert.deepEqual(actual, expected, "should extract by definition order");
actual = _.extract([{ a: 1 }, { a: 2 }, { a: 3 }], "a");
expected = [1, 2, 3];
assert.deepEqual(actual, expected, "should behave like _.pluck");
actual = _.extract({
"groupby:a": "a",
"stats:foo": "foo",
"groupby:b": "b",
"groupby:c": "c",
"histogram:baz": "baz",
"nested": {
"groupby:d": "d",
"nested": {
"groupby:e": "e"
}
}
}, (value, key) => /^groupby:/.test(key));
expected = ["a", "b", "c", "d", "e"];
assert.deepEqual(actual, expected, "should take a function predicate for filtering");
actual = _.chain({
a1: { value: Math.PI },
a2: { next: { value: Math.E } },
a3: { next: { next: { value: Math.LN10 } } }
})
.extract(function(value, key) { return /^(a1|a3)$/.test(key); })
.extract("value")
.value();
expected = [Math.PI, Math.LN10];
assert.deepEqual(actual, expected, "should be chainable");
actual = _.extract();
expected = [];
assert.deepEqual(actual, expected, "should return an empty array");
actual = [];
_.extract({
"groupby:a": "a",
"stats:foo": "foo",
"groupby:b": "b",
"groupby:c": "c",
"histogram:baz": "baz",
"nested": {
"groupby:d": "d",
"nested": {
"groupby:e": "e"
}
}
}, (value, key) => actual.push(key));
expected = ["groupby:a", "stats:foo", "groupby:b", "groupby:c", "histogram:baz", "groupby:d", "groupby:e", "nested", "nested"];
assert.deepEqual(actual, expected, "should visit every key/value");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment