Created
April 5, 2013 04:15
-
-
Save cannona/5316590 to your computer and use it in GitHub Desktop.
Convert a flat JS object into a nested set of objects and arrays.
This file contains 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
var nester = (function () { | |
/** | |
* Selected Keys from Object | |
* | |
* @param object obj The object from which you want to get the keys. | |
* @param array ignoredKeys keys to ignore. | |
* @return array the non-ignored keys of the object. | |
*/ | |
var selectedKeysFromObject = function (obj, ignoredKeys) { | |
var ignoredKeysObj = {}; | |
for (var i = 0; i < ignoredKeys.length; i++) { | |
ignoredKeysObj[ignoredKeys[i]] = true; | |
} | |
var keys = []; | |
for (key in obj) { | |
if (ignoredKeysObj[key] || !obj.hasOwnProperty(key)) { | |
continue; | |
} | |
keys.push(key); | |
} | |
return keys; | |
}; | |
/** | |
* Populate Object | |
* | |
* A recursive function that adds to a nested object from a flat array and a list of properties. | |
* | |
* @param array source The source array that we wish to nest inside the object. | |
* @param Object destination The object to nest the data inside. | |
* @param array properties A list of properties to be nested, ordered from outer to inner. | |
* @param propertiesIndex internal use, should not be specified by outside calling functions. | |
* @return void | |
*/ | |
var populateObj = function populateObjFunc(source, destination, properties, propertiesIndex) { | |
// the current property we are nesting. | |
if (!propertiesIndex) { | |
propertiesIndex = 0; | |
} | |
var property = properties[propertiesIndex]; | |
propertiesIndex++; | |
// The object matching the current property, and the one being nested. | |
var nestedObj; | |
// Has this property been nested inside this object before? | |
if (!destination[property]) { | |
destination[property] = [] | |
} else { | |
// We found a list, check to see if we can find the nested object matching the property value. | |
for (var i = 0; i < destination[property].length; i++) { | |
if (destination[property][i]['_' + property] === source[property]) { | |
nestedObj = destination[property][i]; | |
break; | |
} | |
} | |
} | |
// Did we find the nested object? If not, create it. | |
if (!nestedObj) { | |
nestedObj = {}; | |
nestedObj['_' + property] = source[property]; | |
destination[property].push(nestedObj); | |
} | |
// if there are more properties to nest, recurse. Otherwise, we've reached the base case. | |
if (properties.length > propertiesIndex) { | |
return populateObjFunc(source, nestedObj, properties, propertiesIndex); | |
} else { | |
// Add the remaining items not in the properties list to the deepest child object. | |
var extraKeys = selectedKeysFromObject(source, properties); | |
for (var i = 0; i < extraKeys.length; i++) { | |
nestedObj[extraKeys[i]] = source[extraKeys[i]]; | |
} | |
return; | |
} | |
}; | |
/** | |
* Anonymous function returned by this function. | |
* | |
* Loops through all the source objects, and nests them. | |
* | |
* @param array records The array of records to be nested. | |
* @param string propertiesString The -> delimited list of properties to nest. | |
*/ | |
return function (records, properties) { | |
var properties = properties.split('->'); | |
var nestedObj = {}; | |
for (var i = 0; i < records.length; i++) { | |
populateObj(records[i], nestedObj, properties); | |
} | |
return nestedObj; | |
}; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment