0

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;
}
2
  • Show us what have you tried. Commented Jan 8, 2016 at 1:00
  • I get why you're checking whether a node has only one child, but why are you checking for whether that child also has children? Is this supposed to only happen at the leaves? If you get rid of the "!data[i].value[0].value" check, I believe you should end up with the structure you want. Commented Jan 8, 2016 at 1:14

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

Comments

0

This version is more understandable. The function either

  • do nothing when it has no value attribute
  • merge with child when it has only one child
  • repeat for every child when there are multiple children

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.