Last active
February 25, 2016 15:43
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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