VΛVΛV
VΛVΛV

Reputation: 93

Javascript Recursive Merge of Hierarchical Data Based on Key

I have a set of arrays:

sample = [
{
    'name' : 'alpha',
    'inner' : [
        {
            'name' : 'beta',
            'inner' : [
                {
                    'name' : 'gamma',
                    'inner' : [
                        {
                            'name' : 'one',
                            'inner' : []
                        }
                    ]
                }
            ]
        }
    ]
},
{
    'name' : 'alpha',
    'inner' : [
        {
            'name' : 'beta',
            'inner' : [
                {
                    'name' : 'gamma',
                    'inner' : [
                        {
                            'name' : 'two',
                            'inner' : []
                        }
                    ]
                }
            ]
        }
    ]
},
{
    'name' : 'epsilon',
    'inner' : [
        {
            'name' : 'one',
            'inner' : []
        }
    ]
},
{
    'name' : 'epsilon',
    'inner' : [
        {
            'name' : 'two',
            'inner' : []
        }
    ]
}
]

Which i would like to merge recursively into this:

sample = [
{
    'name' : 'alpha',
    'inner' : [
        {
            'name' : 'beta',
            'inner' : [
                {
                    'name' : 'gamma',
                    'inner' : [
                        {
                            'name' : 'one',
                            'inner' : []
                        },
                        {
                            'name' : 'two',
                            'inner' : []
                        }
                    ]
                }
            ]
        }
    ]
},
{
    'name' : 'epsilon',
    'inner' : [
        {
            'name' : 'one',
            'inner' : []
        },
        {
            'name' : 'two',
            'inner' : []
        }
    ]
}]

Here is what i have so far:

As i understand this is how it should work, meaning that having a recursive that goes into each "inner" and then merges the arrays.

function _merge(arr) {
//
var result = [];
//
for (var i = 0; i < arr.length; i++) {
    var found = false;
    //
    for (var j = 0; j < result.length; j++) {
        //
        if ( result[j].name == arr[i].name) {
            found = true;
            //
            result[j].inner = result[j].inner.concat(arr[i].inner);
            //
            break;
        }
    }
    if (!found) {
        //
        result.push(arr[i]);
        //
    }
}
//
return result
//
}

//
function traverse(o ) {
    for (i in o) {
        if (!!o[i] && typeof(o[i])=="object") {
            //
            try{
                //
                build_array[i] = _merge(o[i])
                //
            }catch(e){
                //
                build_array = o[i]
                //
            }
            //
            traverse(o[i].inner );
        }
    }
}   
//

Thank you for you help

Upvotes: 0

Views: 319

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386560

You could use an iterative and recursive approach for merging same named objects.

var data = [{ name: 'alpha', inner: [{ name: 'beta', inner: [{ name: 'gamma', inner: [{ name: 'one', inner: [] }] }] }] }, { name: 'alpha', inner: [{ name: 'beta', inner: [{ name: 'gamma', inner: [{ name: 'two', inner: [] }] }] }] }, { name: 'epsilon', inner: [{ name: 'one', inner: [] }] }, { name: 'epsilon', inner: [{ name: 'two', inner: [] }] }],
    result = [];

data.forEach(function iter(r) {
    return function (a) {
        var o;
        if (!r.some(function (b) { if (a.name === b.name) { o = b; return true; } })) {
            r.push(a);
            return;
        }
        Array.isArray(a.inner) && a.inner.forEach(iter(o.inner = o.inner || []));
    };
}(result));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

For additional properties you could add

Object.keys(a).forEach(function (k) {
    if (['name', 'inner'].indexOf(k) === -1) {
        o[k] = a[k];
    }
});

for iteration all properties and assign only the keys which are not name or inner.

var data = [{ name: 'alpha', data1: '1', inner: [{ name: 'beta', data2: '2', inner: [{ name: 'gamma', data3: '3', inner: [{ name: 'one', data4: '4', inner: [] }] }] }] }, { name: 'alpha', data5: '5', inner: [{ name: 'beta', data6: '6', inner: [{ name: 'gamma', data7: '7', inner: [{ name: 'two', data8: '8', inner: [] }] }] }] }, { name: 'epsilon', data9: '9', inner: [{ name: 'one', data10: '10', inner: [] }] }, { name: 'epsilon', data11: '11', inner: [{ name: 'two', data12: '12', inner: [] }] }],
    result = [];

data.forEach(function iter(r) {
    return function (a) {
        var o;
        if (!r.some(function (b) { if (a.name === b.name) { o = b; return true; } })) {
            r.push(a);
            return;
        }
        Object.keys(a).forEach(function (k) {
            if (['name', 'inner'].indexOf(k) === -1) {
                o[k] = a[k];
            }
        });
        Array.isArray(a.inner) && a.inner.forEach(iter(o.inner = o.inner || []));
    };
}(result));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

behzad besharati
behzad besharati

Reputation: 6910

This is what u want:

function merge(sourceArray,lastResult){

                    var output=lastResult || [];
                    sourceArray.forEach(function(sourceItem){

                        var founded=output.filter(function(item){
                            return item.name==sourceItem.name;
                        })[0];

                        if(!founded){
                            founded={
                                name:sourceItem.name,
                                inner:[]
                            };
                            output.push(founded);
                        }


                        founded.inner= merge(sourceItem.inner||[],founded.inner)
                    });
                    return output;
                }


                var source = [
                    {
                        'name' : 'alpha',
                        'inner' : [
                            {
                                'name' : 'beta',
                                'inner' : [
                                    {
                                        'name' : 'gamma',
                                        'inner' : [
                                            {
                                                'name' : 'one',
                                                'inner' : []
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        'name' : 'alpha',
                        'inner' : [
                            {
                                'name' : 'beta',
                                'inner' : [
                                    {
                                        'name' : 'gamma',
                                        'inner' : [
                                            {
                                                'name' : 'two',
                                                'inner' : []
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        'name' : 'epsilon',
                        'inner' : [
                            {
                                'name' : 'one',
                                'inner' : []
                            }
                        ]
                    },
                    {
                        'name' : 'epsilon',
                        'inner' : [
                            {
                                'name' : 'two',
                                'inner' : []
                            }
                        ]
                    }
                ];

                console.log(merge(source));

Upvotes: 1

Related Questions