Reputation: 315
I want all of the individual nodes in the tree all merged into its parent, but if its child nodes contain two or more child nodes, without any change。
Here is my data model example:
[{
name: "HOME",
value: [{//Only node merged into the parent level
name: "HOME",
value: [{//Only node merged into the parent level
name: "HOME",
id: '1000'
}]
}]
}, {
name: "ARTICLE",
value: [{
name: "ARTICLE",
value: [{
name: "ARTICLE TYPE 1",
id: '2001'
},{
name: "ARTICLE TYPE 2",
id: '2002'
}]
},{
name: "ARTICLE",
value: [{//Only node merged into the parent level
name: "ARTICLE TYPE 3",
id: '2003'
}]
}]
}]
I want to filter the data get like this:
[{
name: "HOME",
id: 1000
}, {
name: "ARTICLE",
value: [{
name: "ARTICLE",
value: [{
name: "ARTICLE TYPE 1",
id: '2001'
},{
name: "ARTICLE TYPE 2",
id: '2002'
}]
},{
name: "ARTICLE TYPE 3",
id: '2003'
}]
}]
//Update 1: This is the idea, but now there is a problem, find the node can not fall back to the original node, you can only modify the current parent node:
function filter(data){
for(var i = 0; i < data.length; i++){
if( !data[i].value ) continue;
//Check whether there are child nodes "value" is because it contains a "value" does not exist "id",
//you must enter a recursive make the following checks
if( data[i].value.length === 1 && !data[i].value[0].value ) {
data[i].id = data[i].value[0].id;
delete data[i].value;
continue;
}
filter( data[i].value );
}
return data;
}
I am now directly modify the original object, I do not know whether it is reasonable to do so.
//Update 2: My final wording is like this, the resulting output appears to be correct, but are not sure the logic is correct, and it looks very ugly, or do not know whether there is a better solution?
function filter(data, parent){
for(var i = 0; i < data.length; i++){
if( data[i].value ) filter( data[i].value, data[i] );
if( parent && data.length === 1 && !data[i].value ) {
parent.id = data[i].id;
delete parent.value;
}
}
return data;
}
Upvotes: 0
Views: 663
Reputation: 3593
a simple version
function merge(node){
if(node.value){
var children = node.value.map(merge);
return children.length === 1?
children[0]:
{
name: node.name,
value: children
};
}
return node;
}
var result = data.map(merge);
or so:
function cp(a, b){
for(var k in b){
if(k === "value" || k in a) continue;
a[k] = b[k];
}
return a;
}
function merge(node){
if(node.value){
var children = node.value.map(merge);
return children.length===1 && !("value" in children[0])?
cp(children[0], node):
cp({ value: children }, node);
}
return cp({}, node);
}
var result = data.map(merge);
Upvotes: 1
Reputation: 12772
This version is more understandable. The function either
var data = [{
name: "HOME",
value: [{//Only node merged into the parent level
name: "HOME",
value: [{//Only node merged into the parent level
name: "HOME",
id: '1000'
}]
}]
}, {
name: "ARTICLE",
value: [{
name: "ARTICLE",
value: [{
name: "ARTICLE TYPE 1",
id: '2001'
},{
name: "ARTICLE TYPE 2",
id: '2002'
}]
},{
name: "ARTICLE",
value: [{//Only node merged into the parent level
name: "ARTICLE TYPE 3",
id: '2003'
}]
}]
}];
function merge(node) {
if (node.value == undefined) return;
if (node.value.length == 1) {
var child = node.value[0];
node.name = child.name;
if (child.id) node.id = child.id;
if (child.value) node.value = child.value;
else delete node.value;
merge(node);
} else {
node.value.forEach(function(child) {
merge(child);
});
}
}
$('#input').html(JSON.stringify(data));
data.forEach(function(node) { merge(node) });
$('#output').html(JSON.stringify(data));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Input: <div id="input"></div>
Output: <div id="output"></div>
Upvotes: 0