1

I want to convert an object from one format to another. So far my attempts at doing this recursively failed; either I'm getting a maximum stack exception or I'm unable to iterate over all paths.

Let's assume we have an object that lists questions and their answers. There may be N questions and M answers.

Object at start:

var before = {
    item: 'Question 1',
    id: '1',
    type: 'Question',
    items: [
        {
            item: 'Answer 1',
            id: '1.1',
            type: 'Answer',
            items:
            [
                {
                    item: 'Question 2',
                    id: '1.1.1',
                    type: 'Question',
                    items: [
                        {
                            item: 'Answer 2.1',
                            id: '1.1.1.1',
                            type: 'Answer'
                        },
                        {
                            item: 'Answer 2.2',
                            id: '1.1.1.2',
                            type: 'Answer'
                        }
                    ]
                }   
                // ...          
            ]
        }, {
            item: 'Answer 1',
            id: '1.2',
            type: 'Answer',
            items:
            [
                {
                    item: 'Question 3',
                    id: '1.2.1',
                    type: 'Question',
                    items: [
                        {
                            item: 'Answer 3.1',
                            id: '1.2.1.1',
                            type: 'Answer'
                        },
                        {
                            item: 'Answer 3.2',
                            id: '1.2.1.2',
                            type: 'Answer'
                        }
                    ]
                }   
                // ...          
            ]
        }
        // ...
    ]
}

Object how it should look like (wrap all in 'items' array; change key names 'item' to 'title', 'id' to 'key', remove 'type', add 'color' depending on 'type'):

var after = {
    items: [
        {
            title: 'Question 1',
            key: '1',
            color: 'Red',
            items: [
                {
                    title: 'Answer 1',
                    key: '1.1',
                    color: 'Blue',
                    items:
                    [
                        {
                            title: 'Question 2',
                            key: '1.1.1',
                            color: 'Red',
                            items: [
                                {
                                    title: 'Answer 2.1',
                                    key: '1.1.1.1',
                                    color: 'Blue'
                                },
                                {
                                    title: 'Answer 2.2',
                                    key: '1.1.1.2',
                                    color: 'Blue'
                                }
                            ]
                        }   
                        // ...          
                    ]
                }, {
                    title: 'Answer 1',
                    key: '1.2',
                    color: 'Blue',
                    items:
                    [
                        {
                            title: 'Question 3',
                            key: '1.2.1',
                            color: 'Red',
                            items: [
                                {
                                    title: 'Answer 3.1',
                                    key: '1.2.1.1',
                                    color: 'Blue'
                                },
                                {
                                    title: 'Answer 3.2',
                                    key: '1.2.1.2',
                                    color: 'Blue'
                                }
                            ]
                        }   
                        // ...          
                    ]
                }
                // ...
            ]
        }
    ]
}

It seems easy enough, but I can't get it to work. This is how I tried to iterate:

function iter(o) {
    for(let k in o) {
        if (!(['item', 'items', 'id'].includes(k))) // My object contains a few more keys I don't want to go down further into
            continue

        if (o[k] !== null && typeof o[k] === 'object') {
            iter(o[k]); // Max stack exception
            return;
        }
    }
};

Thank you very much!

2 Answers 2

3

You could map the objects and rename the keys and map nested items.

const
    iter = ({ item: title, id: key, type, items, ...o }) => ({
        title,
        key,
        color: 'color' + key,
        ...o,
        ...(items && { items: items.map(iter) })
    }),
    before = { item: 'Question 1', id: '1', type: 'Question', items: [{ item: 'Answer 1', id: '1.1', type: 'Answer', items: [{ item: 'Question 2', id: '1.1.1', type: 'Question', items: [{ item: 'Answer 2.1', id: '1.1.1.1', type: 'Answer' }, { item: 'Answer 2.2', id: '1.1.1.2', type: 'Answer' }] }] }, { item: 'Answer 1', id: '1.2', type: 'Answer', items: [{ item: 'Question 3', id: '1.2.1', type: 'Question', items: [{ item: 'Answer 3.1', id: '1.2.1.1', type: 'Answer' }, { item: 'Answer 3.2', id: '1.2.1.2', type: 'Answer' }] }] }] },
    result = [before].map(iter);
     
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

Comments

1

You can achieve this using map, I wrote an simple test to show my point here

this is the important part of the code

function rename(item: any) {
  return {
    title: item.item,
    key: item.id,
    color: item.type === 'Question' ?  'red' : 'blue',
    items: item.items?.map(rename)
  }
}

console.log(items.map(rename))

Of course if you're using typescript, change any to the appropriate type and pay attention that I'm using ? operator which will not work with javascript, so you could do something like

...
items: item.items ? item.items.map(rename) : undefined
... 

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.