Home > Net >  Javascript compare results in a single object array and append if a value matches within the same ob
Javascript compare results in a single object array and append if a value matches within the same ob

Time:11-04

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.

enter image description here

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:

  1. find first element
  2. find childs of this element
  3. check childs of child elements
  4. repeat step 3 until you have whole tree
  5. flatten your tree

Try to do it yourself and only then check this example on how it can be achieved.

Show code snippet

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
  • Related