I was working on a solution to another question posed, and I came up with a solution, but I'm convinced that there's a more elegant way to do it. Let's say that you have an object where all of the values are a string of values separate by commas, like this:
{ "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
But, you'd like to separate the values and break up the object into an array of objects, like this:
[
{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }
]
Here's what my solution was:
var actions = obj.action.split(',');
var targets = obj.target.split(',');
// combined the actions and targets arrays
var combinedData = _.zip(actions, targets);
// go through the combinedData array and create an object with the correct keys
var commandList = _.map(combinedData, function(value) {
return _.object(["action", "target"], value)
});
This does what I want and doesn't look terrible, but is there a slicker way of accomplishing this?
Functional style is great. Here's a more direct approach.
var newObjects = [];
for(var k in o) {
var vals = o[k].split(',');
for(var i = 0, len = vals.length; i < len; i++) {
newObjects[i] = newObjects[i] || {};
newObjects[i][k] = vals[i];
}
}
I wouldn't worry too much about the implementation until you come up with a nice, compact, semantic name for this operation. Any ideas?
So, I did a little refactoring of my code to create a more functional and cleaner looking answer:
var obj = { "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
// separate and split the values form the object
function separate(obj) {
return _.map( _.values( obj ), function(value) {
return value.split(',');
});
}
// returns [[ "goto", "goto"], ["http://www.google.com", "http://www.cnn.com"]]
// call separate and recombine the values with zip
function separateAndRecombine(obj) {
return _.zip.apply(_, separate(obj));
}
// returns [[ "goto", "http://www.google.com"], ["goto", "http://www.cnn.com"]]
// accept an object that has properties with a string of values
// separated by commas, and separate the values to create an array of objects
function unwind(obj) {
return _.map( separateAndRecombine(obj), function(value) {
return _.object(_.keys(obj), value)
});
};
/* returns:
[{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }] */
Now, unwind()
will take an object with any number of properties or values and 'unwind' all of the existing properties.