1

I am trying to transform this object :

[
    {
        "keyword":"apple",
        "category_1":"object",
        "category_2":"living",
        "category_3":"fruit",
        "count":5
    },
    {
        "keyword":"orange",
        "category_1":"object",
        "category_2":"living",
        "category_3":"fruit",
        "count":1
    },
    {
        "keyword":"table",
        "category_1":"object",
        "category_2":"non living",
        "category_3":"house item",
        "count":3
    },
    {
        "keyword":"cat",
        "category_1":"object",
        "category_2":"living",
        "category_3":"animal",
        "count":4
    },
    {
        "keyword":"stadium",
        "category_1":"place",
        "category_2":"sport related",
        "category_3":"indoor",
        "count":2
    }
]

into an object like this :

[
    {
        label: 'object',
        count: 9,
        childs: [
            {
                label: 'living',
                count: 6,
                childs: [
                    {
                        label: 'fruit',
                        count: 6,
                        childs: [
                            {
                                keyword: 'apple',
                                count: 5,
                            },
                            {
                                keyword: 'orange',
                                count: 1,
                            }
                        ]
                    }
                ]
            },
            {
                label: 'non living',
                count: 3,
                childs: [
                    {
                        label: 'animal',
                        count: 3,
                        childs: [
                            {
                                keyword: 'cat',
                                count: 3,
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        label: 'place',
        count: 2,
        childs: [
            {
                label: 'sport related',
                count: 2,
                childs: [
                    {
                        label: 'indoor',
                        count: 2,
                        childs: [
                            {
                                keyword: 'stadium',
                                count: 2,
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

I tried with Array.reduce in a recursive manner, but I have troubles with recursivity, I always end up hitting a wall. As you can see, the point is to turn the array into a nested object grouping its elements by category (the count part is not essential)

If anyone has any hindsight on this

3
  • 2
    Why not children instead of childs? Commented Oct 28, 2019 at 11:20
  • shouldn't objects count be 13? Commented Oct 28, 2019 at 11:44
  • There's also a cat missing and three tables ;P Commented Oct 28, 2019 at 11:49

1 Answer 1

2

You could first turn the data into nested Maps, each keyed by the relevant category. This allows for quick identification of the correct branch where to inject the next object.

Then apply a recursive function on that to turn that Map-based tree into the target structure, while bubbling up the counts.

Code:

function makeTree(data) {
    // Create tree using nested Maps, keyed by category
    let main = new Map;
    for (let {keyword, category_1, category_2, category_3, count} of data) {
        let obj = { keyword, count };
        let map = main;
        for (let cat of [category_1, category_2, category_3]) {
            let child = map.get(cat);
            if (!child) map.set(cat, child = new Map);
            map = child;
        }
        let child  = map.get(keyword);
        if (!child) map.set(keyword, child = { keyword, count: 0 });
        child.count +=  count;
    }

    // Recursive function to turn the nested Maps into the target structure
    function transform(data) {
        let parentCount = 0;
        let arr = Array.from(data, ([label, value]) => {
            let count, children;
            if (value instanceof Map) {
                ([children, count] = transform(value));
                value = { label, count, children };
            } else {
                ({ count } = value);
            }
            parentCount += count;
            return value;        
        });
        return [arr, parentCount];
    }
    return transform(main)[0];
}

// Example run:
let data = [{"keyword":"apple","category_1":"object","category_2":"living","category_3":"fruit","count":5},{"keyword":"orange","category_1":"object","category_2":"living","category_3":"fruit","count":1},{"keyword":"table","category_1":"object","category_2":"non living","category_3":"house item","count":3},{"keyword":"cat","category_1":"object","category_2":"living","category_3":"animal","count":4},{"keyword":"stadium","category_1":"place","category_2":"sport related","category_3":"indoor","count":2}];

console.log(makeTree(data));

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.