I have input data like:
['Level 1/Level 2/Level 3/ Level4a',
'Level 1/Level 2/Level 3/ Level4b',
'Level 1/Level 2/Level 3/ Level4c',
'Level 1/Level 2/Level 3/ Level4a',
'Level 1c/Level 2d/Level 3b/ Level4d',
'Level 1c/Level 2d/Level 3b/ Level4e',
'Level 1c/Level 2d/Level 3b/ Level4f']
Now I would like to convert it to treeview array like this:
tree: [
{
name: 'Level 1',
children: [
{
name: 'Level 2',
children: [
{
name: 'Level 3',
children: [
{name: 'Level 4a'},
{name: 'Level 4b'},
{name: 'Level 4c'}
]
}
]
}
]
},
{
name: 'Level 1c',
children: [
{
name: 'Level 2d',
children: [
{
name: 'Level 3b',
children: [
{name: 'Level 4d'},
{name: 'Level 4e'},
{name: 'Level 4f'}
]
}
]
}
]
}
]
There is a way to iterate, but its to much complex, I guess. What is the best optimal way to do this?
asked Oct 30, 2018 at 14:22
ulou
5,9326 gold badges40 silver badges51 bronze badges
-
please add what you have tried. is the data sorted?Nina Scholz– Nina Scholz2018年10月30日 14:24:45 +00:00Commented Oct 30, 2018 at 14:24
-
btw, the given data does not match the wanted result.Nina Scholz– Nina Scholz2018年10月30日 14:26:20 +00:00Commented Oct 30, 2018 at 14:26
-
@NinaScholz Yes data is sortedulou– ulou2018年10月30日 14:37:34 +00:00Commented Oct 30, 2018 at 14:37
2 Answers 2
You could take an array of the last inserted objects and check if the name is not equal to the last one. if so, add a new object.
var data = ['Level 1/Level 2/Level 3/Level4a', 'Level 1/Level 2/Level 3/Level4b', 'Level 1/Level 2/Level 3/Level4c', 'Level 1/Level 2/Level 3/Level4a', 'Level 1c/Level 2d/Level 3b/Level4d', 'Level 1c/Level 2d/Level 3b/Level4e', 'Level 1c/Level 2d/Level 3b/Level4f'],
tree = [],
levels = [{ children: tree }];
data.forEach(s => s.split('/').forEach((name, i) => {
if (!levels[i + 1] || levels[i + 1].name !== name) {
levels[i].children = levels[i].children || [];
levels[i].children.push(levels[i + 1] = { name });
}
}));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
answered Oct 30, 2018 at 15:00
Nina Scholz
388k26 gold badges367 silver badges417 bronze badges
Sign up to request clarification or add additional context in comments.
3 Comments
LazioTibijczyk
This will not work well if data array is mixed and for instance last data element will start with 'Level 1' again.
Nina Scholz
@LazioTibijczyk, the data is sorted, as op has stated.
LazioTibijczyk
Oh yes, I apologize. Your solution will work in the case when data is sorted.
You can use 2 reduces. The first one is to loop thru the array. The second reduce is to loop thru the split() string. Use find() to check an element exist on an array
var arr = ['Level 1/Level 2/Level 3/ Level4a', 'Level 1/Level 2/Level 3/ Level4b', 'Level 1/Level 2/Level 3/ Level4c', 'Level 1/Level 2/Level 3/ Level4a', 'Level 1c/Level 2/Level 3/ Level4d', 'Level 1c/Level 2/Level 3/ Level4e', 'Level 1c/Level 2/Level 3/ Level4f'];
var result = arr.reduce((c, v) => {
v.split('/').reduce((a, o, i) => {
if (i === 0) var p = a;
else var p = a.children = a.children || [];
let f = p.find(x => x.name === o.trim());
if (!f) {
f = {name: o.trim()};
p.push(f);
}
return f;
}, c);
return c;
}, []);
console.log(result);
answered Oct 30, 2018 at 15:13
Eddie
26.8k6 gold badges39 silver badges59 bronze badges
Comments
lang-js