Find all the linked items to a particular item in an Object Array in JavaScript

Viewed 96

I have an array of objects. You'll be able to find a sample of complete data here on JSONBlob.com.

Here's a simplified preview:

[
  {
    "name": "Unbetitelt",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [{
      "i": "60a64930cf1db1710b97bf7a",
    }],
    "id": "60a6472ecf1db1710b97bf4c"
  },
  {
    "name": "middleparent",
    "parentCubo": "60a6472ecf1db1710b97bf4c",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [{
        "i": "60a64936cf1db1710b97bf7d",
      },
      {
        "i": "60a649afcf1db1710b97bfa6",
      }
    ],
    "id": "60a64930cf1db1710b97bf7a"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a64930cf1db1710b97bf7a",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [
      {
        "i": "60a6494acf1db1710b97bf8f",
      },
      {
        "i": "60a64976cf1db1710b97bf9a",
      }
    ],
    "id": "60a64936cf1db1710b97bf7d"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a64930cf1db1710b97bf7a",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [],
    "id": "60a649afcf1db1710b97bfa6"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a649c5cf1db1710b97bfb1",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [],
    "id": "60a649efcf1db1710b97bfc4"
  }
]

Each object in this array(the root array) has an id and childrenLayout property.

The childrenLayout property is an array(the child array) of Objects which will have an i property but won't have another childrenLayout. So in order to find children of each item in the childrenLayout array, we'll have to use this i field and find objects in the root array.

Once we find those objects in the root array, if the childrenLayout property on those objects is not an empty array, then we have to repeat the same process and find objects in this object's childrenLayout, thereby creating a list of all ids that are linked to one specific object with id x.

So, for instance, if we try to find all the items linked with id 60a6472ecf1db1710b97bf4c, we'll get:

  • 60a64930cf1db1710b97bf7a
  • 60a64936cf1db1710b97bf7d
  • 60a649afcf1db1710b97bfa6
  • 60a6494acf1db1710b97bf8f
  • 60a64976cf1db1710b97bf9a

This is what I have so far and it's obviously not working as expcted and only returns the last three items from the expected items list mentioned above:

const findChildFor = item => {
  if (item.childrenLayout.length > 0) {
    const detailsOfItems = item.childrenLayout.map(({ i }) =>
      data.find(datum => datum.id === i)
    );
    return detailsOfItems.map(itemDetails => findChildFor(itemDetails));
  } else {
    return item.id;
  }
};
const [firstItem] = data;
// TODO: Work on a way to make it return children without having to flatten it.
const childrenRelatedToFirstItem = findChildFor(firstItem);
console.log(
  'childrenRelatedToFirstItem: ',
  childrenRelatedToFirstItem.flat(10)
);

To help speed up the solution, here's a Sample Stackblitz with the code so far.

Any help is greatly appreciated.

3 Answers

I found a solution. Code isn't so complex. Hoping this would be helpful.

const findChildFor = (arr, id, output) => {
    const item = arr.find(obj => obj.id === id);
    if (item) {
        const childs = item.childrenLayout;
        for (let child of childs) {
            output.push(child.i);
            findChildFor(arr, child.i, output);
        }
    }
}

output = [];
findChildFor(data, '60a6472ecf1db1710b97bf4c', output);
console.log(output);

This data looks like a graph description. Here is my solution for the problem with optimized time complexity and taking care of cyclic connections.

const findAllChildren = (arr, id) => {
  // to find each child with O(1) access time
  const familyMap = new Map(arr.map(it => [it.id, it.childrenLayout]));
  // to check if a child has been collected with O(1) access time   
  const resultSet = new Set();
  const findChildrenFor = (parentId) => {
    familyMap.get(parentId).forEach(({i}) => {
      // in a case of a cyclic graph
      if (!resultSet.has(i)) {
        resultSet.add(i);
        findChildrenFor(i);
      }
    });
  };
  return Array.from(findChildrenFor(id));
};

I through in a solution in a different way but with the result that you want.

dataArray.reduce((acc,cur)=>{
    acc[cur.id] = [];
    cur.childrenLayout.map(child=>acc[cur.id].push(child.i))
    Object.entries(acc).map(obj=>{
       if(obj[1].includes(cur.id)){
          cur.childrenLayout.map(child=>acc[obj[0]].push(child.i))
       }
    })
   return acc;
},{})

Any question leave it in the comments section.

const dataArray = [
  {
    "name": "Unbetitelt",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [{
      "i": "60a64930cf1db1710b97bf7a",
    }],
    "id": "60a6472ecf1db1710b97bf4c"
  },
  {
    "name": "middleparent",
    "parentCubo": "60a6472ecf1db1710b97bf4c",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [{
        "i": "60a64936cf1db1710b97bf7d",
      },
      {
        "i": "60a649afcf1db1710b97bfa6",
      }
    ],
    "id": "60a64930cf1db1710b97bf7a"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a64930cf1db1710b97bf7a",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [
      {
        "i": "60a6494acf1db1710b97bf8f",
      },
      {
        "i": "60a64976cf1db1710b97bf9a",
      }
    ],
    "id": "60a64936cf1db1710b97bf7d"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a64930cf1db1710b97bf7a",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [],
    "id": "60a649afcf1db1710b97bfa6"
  },
  {
    "name": "Unbetitelt",
    "parentCubo": "60a649c5cf1db1710b97bfb1",
    "organizationMap": "60a55ed4e3a8973a02f910f1",
    "childrenLayout": [],
    "id": "60a649efcf1db1710b97bfc4"
  }
]

const childFinder = arr => {
  return arr.reduce((acc,cur)=>{
    acc[cur.id] = [];
cur.childrenLayout.map(child=>acc[cur.id].push(child.i))
Object.entries(acc).map(obj=>{
    if(obj[1].includes(cur.id)){
cur.childrenLayout.map(child=>acc[obj[0]].push(child.i))
    }
})
return acc;
},{})
}

console.log(childFinder(dataArray))

Related