Reputation: 692
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
Upvotes: 1
Views: 86
Reputation: 350079
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));
Upvotes: 2