I'm looking to try and concatenate the array down to the base folder hierarchy.
In my example below "Level 1" is the lowest level there are no children folders to this level. The "other level" will have a multitude of different folders all under the "Top Level"
The array I have the data is as follows:
[{ id: "Top Level", outerpath: "test plan", innerpath: "Regression" },
{ id: "other level", outerpath: "Regression", innerpath: "area 1" },
{ id: "Level 1", outerpath: "area 1", innerpath: "Subarea 1" },
{ id: "Level 1", outerpath: "area 1", innerpath: "Subarea 2" },
{ id: "Level 1", outerpath: "Regression", innerpath: "area 2" }]
Now I needing the results of the concaternation of the data within the object array to look like this:
test plan/Regression/area 1/Subarea 1
test plan/Regression/area 1/Subarea 2
test plan/Regression/area 2
However I have no clue how to start this. Perhaps its along the lines of a loop through the array matching "innerpath" and "outpath" values then pushing the completed data to another array?
Any ideas would be really useful.
UPDATE:
To expand on my question the array is dynamic and depending of the results of the API it might be like this array
[{ id: "Top Level", outerpath: "test plan", innerpath: "Regression" }
{ id: "other level", outerpath: "Regression", innerpath: "area 1" }
{ id: "Level 1", outerpath: "area 1", innerpath: "Subarea 1" }
{ id: "other level", outerpath: "area 1", innerpath: "Subarea 2" }
{ id: "Level 1", outerpath: "Regression", innerpath: "area 2" }
{ id: "Top Level", outerpath: "test plan", innerpath: "other testing" }
{ id: "Level 1", outerpath: "other testing", innerpath: "other testing area 1" }
{ id: "other level", outerpath: "other testing", innerpath: "other testing area 2" }
{ id: "Level 1", outerpath: "other testing area 2", innerpath: "other testing subarea 1" }
{ id: "Level 1", outerpath: "Subarea 2", innerpath: "SubSubArea 1" }]
So there isn't going to be just one top level it could be multiple top levels as the folder "test plan" will have multiple folders with some of them with subfolders of their own.
My code that collated the data from the callback from the API call is here:
let testSuiteData = res;
testSuiteData.value.forEach(async testSuiteItem => {
console.log(testSuiteItem);
if(!testSuiteItem.hasChildren === true) // Level 1
{
console.log(testSuiteItem.parentSuite.name '/' testSuiteItem.name)
folderHierarchy.path.push({
id: 'Level 1',
outerpath: testSuiteItem.parentSuite.name,
innerpath: testSuiteItem.name
})
}
else if(testSuiteItem.hasChildren === true ) // other levels
{
if(testSuiteItem.parentSuite.name === testSuiteItem.plan.name) // Top Level
{
console.log(testSuiteItem.parentSuite.name '/' testSuiteItem.name)
folderHierarchy.path.push({
id: 'Top Level',
outerpath: testSuiteItem.parentSuite.name,
innerpath: testSuiteItem.name
})
}
else{ // Other Levels
console.log(testSuiteItem.parentSuite.name '/' testSuiteItem.name)
folderHierarchy.path.push({
id: 'other level',
outerpath: testSuiteItem.parentSuite.name,
innerpath: testSuiteItem.name
})
}
}
console.log(folderHierarchy.path);
CodePudding user response:
You could do something like this
const array = [{ id: "Top Level", outerpath: "test plan", innerpath: "Regression" },
{ id: "other level", outerpath: "Regression", innerpath: "area 1" },
{ id: "Level 1", outerpath: "area 1", innerpath: "Subarea 1" },
{ id: "Level 1", outerpath: "area 1", innerpath: "Subarea 2" },
{ id: "Level 1", outerpath: "Regression", innerpath: "area 2" }]
const obj = {}; // a map of all our paths
const topLevel = array.splice(0, 1)[0]; // removing the top level from array as it is not needed, and for further reference
const base = `${topLevel.outerpath}/${topLevel.innerpath}`; // creating our default path, which we will use as a reference later
for (let i = 0; i < array.length; i ) {
const path = array[i].outerpath.split(' '); // creating a unique key for our map
const key = path[1] ? path[1] : path[0];
if (!obj[key]) obj[key] = [];
if (path[0] == 'area')
obj[key].push(`${base}/${array[i].outerpath}/${array[i].innerpath}`);
else if (path[0] == 'Regression')
obj[key].push(`${base}/${array[i].innerpath}`)
}
console.log(obj);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
My approach in steps:
- find first element
- find childs of this element
- check childs of child elements
- repeat step 3 until you have whole tree
- flatten your tree
Try to do it yourself and only then check this example on how it can be achieved.
class TreeList {
tree = null;
isTopLevel = (level) => {
let topLevel = true;
this.data.map(lv => {
if (lv.innerPath === level.outerPath) {
topLevel = false;
}
});
return topLevel;
}
createTree = (data) => {
this.data = data;
data.map(level => {
if (this.isTopLevel(level)) {
this.tree = level;
}
});
if (this.tree === null) {
console.error('Couldn\'t find top level.');
return;
}
this.tree = this.findChildLevels(this.tree);
return this.flattenObject(this.tree);
}
findChildLevels = (level) => {
this.data.map(lv => {
if (lv.outerPath === level.innerPath) {
if (level?.children === null || level?.children === undefined) {
level.children = [];
}
level.children.push(this.findChildLevels(lv));
}
});
return level;
}
flattenObject = (level) => {
let currentPath = level.outerPath;
let list = [];
if (level?.children !== undefined && level?.children !== null) {
level.children.map(child => {
this.flattenChildren(list, currentPath, child);
});
} else {
list = [currentPath];
}
return list
}
flattenChildren = (list, currentPath, level) => {
if (level?.children !== undefined && level?.children !== null) {
// currentPath = `/${level.outerPath}`;
currentPath = '/' level.outerPath;
level.children.map(child => {
this.flattenChildren(list, currentPath, child)
});
} else {
// list.push(`${currentPath}/${level.outerPath}/${level.innerPath}`);
list.push(currentPath '/' level.outerPath '/' level.innerPath);
}
return list;
}
}
const tl = new TreeList()
const list = tl.createTree([
{id: "Top Level", outerPath: "test plan", innerPath: "Regression"},
{id: "other level", outerPath: "Regression", innerPath: "area 1"},
{id: "Level 1", outerPath: "area 1", innerPath: "Subarea 1"},
{id: "Level 1", outerPath: "area 1", innerPath: "Subarea 2"},
{id: "Level 1", outerPath: "Regression", innerPath: "area 2"}
]);
list.map(item => {
console.log(item);
});
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
I think we can simplify this a bit more by first creating a list of all unique innerpath
values which do not also appear as outerpath
values and then traversing backwards from each.
Here's how that would look, using your latest dynamic array of objects:
I excluded the
id
property values from your original data, as it did not appear to be getting used anywhere, just for the sake of keeping this example concise, but you can certainly add that back in your final version.
const data = [
{ outerpath: "test plan", innerpath: "Regression" },
{ outerpath: "Regression", innerpath: "area 1" },
{ outerpath: "area 1", innerpath: "Subarea 1" },
{ outerpath: "area 1", innerpath: "Subarea 2" },
{ outerpath: "Regression", innerpath: "area 2" },
{ outerpath: "test plan", innerpath: "other testing" },
{ outerpath: "other testing", innerpath: "other testing area 1" },
{ outerpath: "other testing", innerpath: "other testing area 2" },
{ outerpath: "other testing area 2", innerpath: "other testing subarea 1" },
{ outerpath: "Subarea 2", innerpath: "SubSubArea 1" }
];
const outerpaths = data.map(({ outerpath }) => outerpath),
innerpaths = data.map(({ innerpath }) => innerpath).filter(innerpath => !outerpaths.includes(innerpath));
const concatenated = innerpaths.map(innerpath => {
let obj = data.find(obj => obj.innerpath === innerpath),
str = obj.outerpath '/' innerpath;
if (obj) do {
obj = data.find(({ innerpath }) => obj.outerpath === innerpath);
if (obj) str = obj.outerpath '/' str;
} while (obj)
return str;
});
console.log(concatenated.join('\n'));
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
The output of this code is:
test plan/Regression/area 1/Subarea 1
test plan/Regression/area 2
test plan/other testing/other testing area 1
test plan/other testing/other testing area 2/other testing subarea 1
test plan/Regression/area 1/Subarea 2/SubSubArea 1