user3711421
user3711421

Reputation: 1808

Convert flat json structure to hierarchical

I cannot get my head around this problem.

I have a settings object which looks like

const setting = [
    {
        Key: 'root/',
        Value: null,
    },
    {
        Key: 'root/second-root/',
        Value: null,
    },
    {
        Key: 'root/second-root/names/',
        Value: null,
    },
    {
        Key: 'root/second-root/names/capital-letter',
        Value: true,
    },
    {
        Key: 'root/second-root/countries/',
        Value: null,
    },
    {
        Key: 'root/second-root/countries/enabledcountries',
        Value: 'US,UK,DK',
    },
    {
        Key: 'root/second-root/countries/async',
        Value: 'true',
    },
    {
        Key: 'root/second-root/countries/manual',
        Value: 'true',
    },
    {
        Key: 'root/second-root/countries/limit',
        Value: '4200',
    },
    {
        Key: 'root/second-root/names/onyl-last-name',
        Value: false,
    },
];

I need to convert it to look like

const wantedResult = [
    {
        'root': {
            'Value': null,
            'second-root': {
                'Value': null,
                'names': {
                    'Value': null,
                    'capital-letter': {
                        'Value': true,
                    }
                    'onyl-last-name': {
                        'Value': false,
                    }
                },
                'countries': {
                    'Value': null,
                    'enabledcountries': {
                        Value: 'US,UK,DK',
                    },
                    'async': {
                        Value: 'true',
                    },
                    'manual': {
                        Value: 'true',
                    },
                    'limit': {
                        Value: '4200',
                    }
                }
            }
        }
    }
];

The it is the Key property which controls the hierarchy. If it ends with a / the item is a directory else it is a value.

Problem is that the flat structure doesnt have to return the items in a correct order. Like in the example, the last item is 'root/second-root/names/onyl-last-name', even though the names hiarchy was in the beginning of the flat structure.

I have tried a form of array.reduce but get stuck every time. Could someone please help me.

Upvotes: 2

Views: 833

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386560

You could iterate the array and take the value without the last slash and split it as path to the object for assigning the value.

If necessary put the result in an array.

In forEach works

  • a destructuring assignment for getting the key and value out of the object,

  • a replacement which looks for a slash at the end of the string with an empty string,

  • a splitting of the string by slash, it returns an array with strings without slashes,

  • using Array#reduce with the result object as accumulator.

    Inside it uses a default pattern with a logical OR || which check if the left side is a truthy value and if not, it assigns an object. This value is returned for the check with the next key.

  • at the end of the iteration it retuns an object reference and then the value gets assigned.

var setting = [{ Key: 'root/', Value: null }, { Key: 'root/second-root/', Value: null }, { Key: 'root/second-root/names/', Value: null }, { Key: 'root/second-root/names/capital-letter', Value: true }, { Key: 'root/second-root/countries/', Value: null }, { Key: 'root/second-root/countries/enabledcountries', Value: 'US,UK,DK' }, { Key: 'root/second-root/countries/async', Value: 'true' }, { Key: 'root/second-root/countries/manual', Value: 'true' }, { Key: 'root/second-root/countries/limit', Value: '4200' }, { Key: 'root/second-root/names/onyl-last-name', Value: false }],
    result = {};

setting.forEach(({ Key, Value }) => Key
    .replace(/\/$/, '')
    .split('/')
    .reduce((o, k) => o[k] = o[k] || {}, result).Value = Value
);

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

Upvotes: 3

Related Questions