Reputation: 6646
I honestly have no idea how to explain this in the title, but I tried my best. What I want to do is grab all the objects/values from a string. However, since my objects can contain objects, I want to make sure that works as well. This is what I want to achieve:
var key = "House.Number";
var data = "...";
var output = data.map(item => item[key]);
What this should do, is give me all the house numbers. Simply doing item["House.Number"]
won't work, but if I do item["House"]["Number"]
it works just fine. Is there a quick/good way of doing this? Something like split on .
means new object or something like that?
https://jsfiddle.net/psz4Ltqa/1/
Upvotes: 3
Views: 1231
Reputation: 2908
You need something like this. I am using this function in my project, and it works well.
function nestedValue (obj, key) {
var tmp = obj;
var keys = key.split('.');
for(var i = 0; i < keys.length && tmp; i ++)
tmp = tmp[keys[i]];
return tmp;
}
then use this in map.
var output = data.map(item => nestedValue(item, key));
Upvotes: 0
Reputation: 7352
So basically you need this:
data.map(item => item["House"]["Number"])
But you want to achieve it with a given key
. You can do this:
var keys = key.split('.'), output = data;
for (var i = 0; i < keys.length; i++) {
output = output.map(item => item[keys[i]]);
}
console.log(output);
Upvotes: 1
Reputation: 23382
You can split to a path and loop through the keys like so:
var data = {
One: {
Two: {
Three: 3
}
}
}
var getPath = function(obj, path) {
return path
.split(".") // Create an array of keys
.reduce(function(pos, k) {
return pos.hasOwnProperty(k) ? pos[k] : pos; // Return nested value or, if there isn't, last value
}, obj);
}
console.log(getPath(data, "One.Two"));
console.log(getPath(data, "One.Two.Three"));
(Note that you can decide for your self what you want to do when paths are missing. You can for example return undefined
, or like I chose to do, return the last value you could find)
Now, you can use this in a map
operation like so:
// Switched the argument order to make it more suitable for `map` (data last)
var getPath = function(path, obj) {
return path
.split(".") // Create an array of keys
.reduce(function(pos, k) {
return pos.hasOwnProperty(k) ? pos[k] : pos; // Return nested value or, if there isn't, last value
}, obj);
};
var testData = [
{ One: { Two: { Three: "Three" } } },
{ One: { Two: { Three: 3 } } },
{ One: { Two: { Three: "11" } } }
];
var oneTwoThrees = testData.map(getPath.bind(null, "One.Two.Three"));
console.log(oneTwoThrees);
If you don't like the bind syntax, you can curry the function:
// getPath now returns a function that wraps the path in its closure and waits for the object to get its data from
var getPath = function(path) {
return function(obj) {
return path
.split(".") // Create an array of keys
.reduce(function(pos, k) {
return pos.hasOwnProperty(k) ? pos[k] : pos; // Return nested value or, if there isn't, last value
}, obj);
};
};
var testData = [
{ One: { Two: { Three: "Three" } } },
{ One: { Two: { Three: 3 } } },
{ One: { Two: { Three: "11" } } }
];
var oneTwoThrees = testData.map(getPath("One.Two.Three"));
console.log(oneTwoThrees);
Upvotes: 2
Reputation: 92854
According to your requirement:
What this should do, is give me all the house numbers.
Simple solution using regular for
loop and String.prototype.split()
function:
...
var output = data.map(function(item){
var path = key.split('.'), val = {};
for (var i = 0, len = path.length; i < len; i++) {
val = val[path[i]] || item[path[i]];
}
return val;
});
console.log(output); // all house numbers
The output:
[1, 2, 3, 4]
https://jsfiddle.net/psz4Ltqa/3/
Upvotes: 2