Построение графа объектов из плоского массива объектов в JavaScript
У меня есть массив объектов JavaScript с объектами, которые выглядят так:
Itemid
название
parentItemId <== элементы верхнего уровня без родителя имеют нулевое значение
Я хочу построить график, в котором родительские элементы содержат массивы детей, а эти дети, если применимо, имеют массивы детей.
Какой хороший способ пойти по этому поводу?
3 ответа
function objectGraph(items)
{
var items_by_id = {};
var roots = [];
var i;
// Build an id->object mapping, so we don't have to go hunting for parents
for (i = 0; i < items.length; ++i) {
items_by_id[items[i].itemId] = items[i];
items[i].children = [];
}
for (i = 0; i < items.length; ++i) {
var parentId = items[i].parentItemId;
// If parentId is null, this is a root; otherwise, it's parentId's kid
var nodes = (parentId === null) ? roots : items_by_id[parentId].children;
nodes.push(items[i]);
}
return roots;
}
Обратите внимание, этот код дает каждому узлу children
свойство, пустое, если у узла нет детей. Я лично нахожу это проще и более последовательным, чем у каждого узла, может быть, или, возможно, нет детей; Вы можете перебрать children
не беспокоясь, существует ли он. Листовой узел будет иметь children.length == 0
,
Если вы можете гарантировать, что у вас есть только один корень, вы можете return roots[0];
вместо возврата массива.
Когда вы создаете "функцию построения дерева", вы должны решить, является ли "вещь верхнего уровня" отдельным элементом или массивом элементов. Так как вы сказали itemS, мы идем с массивом. Разница в том, что параметр, который вы передаете и возвращаете, если это массив, мы передаем parentId, в противном случае мы передаем идентификатор.
function buildTree(parentId, list) {
var nodes = [];
for (var i=0, l; l = list[i]; i++) {
if (l.parentId === parentId) {
// if you need "myList" intact afterwards remove the next line at the cost of efficiency
list.splice(i, 1); i--;
nodes.push({
id: l.id
,parentId: l.parentId
,name: l.name
,children: buildTree(l.id, list)
});
}
}
return nodes;
}
var myTree = buildTree(null, myList);
Это немного грубо, но это должно сработать, если я правильно понял ваш вопрос. Он должен возвращать массив объектов верхнего уровня, чьи дочерние элементы правильно расположены под ними.
Как примечание, это будет работать для N-уровня дочерних объектов, а не только для одного уровня.
var finalArray = [];
var YOUR_RAW_ARRAY = [];
var buildObjectGraph = function(inputArray){
var i = 0, len = inputArray.length;
var returnVal = [];
for(;i<len;i++){
if(inputArray[i].parentItemId === null){
findChildren(inputArray[i], inputArray);
returnVal.push(inputArray[i]);
}
}
var findChildren = function(root){
var i = 0, i2 = 0, len = rawDataArray.length, len2 = 0;
for(;i<len;i++){
if(inputArray[i].parentItemId === root.itemId){
if(root.children){
root.children.push(inputArray[i]);
}else{
root.children = [];
root.children.push(inputArray[i]);
}
}
}
//now call it recursively
len2 = root.children.length;
if(len2 > 0){
for(;i2 < len2; i2++){
findChildren(root.children[i2]);
}
}
};
return returnVal;
};
//Then execute it
finalArray = buildObjectGraph(YOUR_RAW_ARRAY);