Home > Software design >  How to find parent on recursive array
How to find parent on recursive array

Time:11-04

I would like to find the parent of a certain item in a recursive array

{
  "uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
  "type": "page",
  "items": [
    {
      "uuid": "9d823429-cc24-444d-a21c-a81357305851",
      "title": "1",
      "type": "question",
    },
    {
      "type": "section",
      "title": "2",
      "uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
      "items": [
        {
          "uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
          "title": "2.1",
          "type": "question",
        }
      ],
    },
    {
      "type": "section",
      "title": "3",
      "uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
      "items": [
        {
          "uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
          "title": "3.1",
          "type": "question",
        }
      ],
    }
  ],
  "params": {
    "collapsed": false
  }
}

I have tried so far:

export const findItemParent = (items, id, parent = null) => {
  if (parent && parent.id === id) {
    return parent;
  }

  for (const item of items) {
    if (Object.prototype.hasOwnProperty.call(item, 'items')) {
      return findItemParent(item.items, id, item);
    }
  }

  return parent;
};

Then I'm calling findItemParent as:

const data = [{...}]; // the data of the first snipet
// b2170580-1e2e-4fb4-a7b9-a56b79db21b3 -> item with title 3.1
const parent = findItemParent(data, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3");

Whenever I run this code I get the parent being 2.

Sandbox

In the case above I'm passing the id of the item with title 3.1 so logically the parent is 3. How can I get the parent of any item given the id?

CodePudding user response:

Using recursion, this is what I've come up with.

The parameter items, I would say is a tad misleading, I would have used something like root.

const findItemParent = (root, id, parent = null) => {
  if (root.uuid === id) return parent;
  if ('items' in root) {
    for (const i of root.items) {
      const r = findItemParent(i, id, root);
      if (r) return r;
    }
  }
  return null;
};

const data = {
  "uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
  "type": "page",
  "items": [
    {
      "uuid": "9d823429-cc24-444d-a21c-a81357305851",
      "title": "1",
      "type": "question",
    },
    {
      "type": "section",
      "title": "2",
      "uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
      "items": [
        {
          "uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
          "title": "2.1",
          "type": "question",
        }
      ],
    },
    {
      "type": "section",
      "title": "3",
      "uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
      "items": [
        {
          "uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
          "title": "3.1",
          "type": "question",
        }
      ],
    }
  ],
  "params": {
    "collapsed": false
  }
};


const findItemParent = (root, id, parent = null) => {
  if (root.uuid === id) return parent;
  if ('items' in root) {
    for (const i of root.items) {
      const r = findItemParent(i, id, root);
      if (r) return r;
    }
  }
  return null;
};

const parent = findItemParent(data, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3");

if (parent) console.log(parent.title, parent.type, parent.uuid);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

const findParent = (currentObject, id, parent = null) => {

  // If its found return its parent
  if (currentObject.uuid === id) return parent;

  // Iterate through sub items 
  for (const item of (currentObject.items) || []) {

    // If found return it
    const found = findParent(item, id, currentObject);
    if (found) return found;

  }
  // If not found return null;
  return null;

};

findParent(el, "346dec94-124c-4932-bd40-af9dc68f1d27");

CodePudding user response:

I would make a map where you have a reference to the parent in the tree. This is helpful if you have a lot of look ups.

const book = {
  "uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
  "type": "page",
  "items": [
    {
      "uuid": "9d823429-cc24-444d-a21c-a81357305851",
      "title": "1",
      "type": "question",
    },
    {
      "type": "section",
      "title": "2",
      "uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
      "items": [
        {
          "uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
          "title": "2.1",
          "type": "question",
        }
      ],
    },
    {
      "type": "section",
      "title": "3",
      "uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
      "items": [
        {
          "uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
          "title": "3.1",
          "type": "question",
        }
      ],
    }
  ],
  "params": {
    "collapsed": false
  }
};

function walkTree(group, parentRef, titleMapping) {
  titleMapping = titleMapping || {}; 
  group.items.forEach(function (item) {
    titleMapping[item.title] = { ...item, parentRef };
    if (item.items) walkTree(item, titleMapping[item.title], titleMapping);
  });
  return titleMapping;
}

const titleMapping = walkTree(book);
console.log(titleMapping["3.1"].parentRef.title);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

Other option is to use a recursive find where you look to see if the items contains the title.

CodePudding user response:

You can use a recursive function to iterate over the items of each item.

const data = {
  "uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
  "type": "page",
  "items": [
    {
      "uuid": "9d823429-cc24-444d-a21c-a81357305851",
      "title": "1",
      "type": "question",
    },
    {
      "type": "section",
      "title": "2",
      "uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
      "items": [
        {
          "uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
          "title": "2.1",
          "type": "question",
        }
      ],
    },
    {
      "type": "section",
      "title": "3",
      "uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
      "items": [
        {
          "uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
          "title": "3.1",
          "type": "question",
        }
      ],
    }
  ],
  "params": {
    "collapsed": false
  }
};

function findItemParent(items, id, parent = null) {
  if (items.find(item => item.uuid === id)) return { uuid: parent?.uuid, type: parent?.type, title: parent?.title };
  for (const item of items) {
    let p;
    if (item.type === 'section') {
      p = findItemParent(item.items, id, item);
    }
    if (p) return p;
  }
}

console.log(findItemParent(data.items, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3"));
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related