-2

I have an array like the below.

 [{
  id: 1,
  is_child_question: false,
  parent_question_id: null },
{
  id: 2,
  is_child_question: true,
  parent_question_id: 1},
{
  id: 3,
  is_child_question: true,
  parent_question_id: 2}]

I want to iterate it and create a new array like below.

[{
  id: 1,
  is_child_question: false,
  parent_question_id: null,
  children: [{
    id: 2,
    is_child_question: true,
    parent_question_id: 1,
    children:[{
      id: 3,
      is_child_question: true,
      parent_question_id: 2,
      }]
  }] 
}]

Like a tree. While iterating if the node has is_child_question === true it should go under its parent node.

Sinto
  • 3,915
  • 11
  • 36
  • 70
  • 1
    right, and what does not work with your code (looks like, you forgot it to add ...) – Nina Scholz Aug 27 '18 at 09:24
  • I am new to javascript. I want to know how it can be achieved either by arrow functions or some other easy way. – Ajay Kumar Sunder Aug 27 '18 at 09:26
  • I'm not sure why you think arrow functions would be relevant here. – Quentin Aug 27 '18 at 09:31
  • Easy way is to iterate over each object in the array and check for the condition you mentioned and push it to children key of the intended parent. This would be pretty easy to implement. – Surabhi K Aug 27 '18 at 09:32
  • @AjayKumarSunder Try following: **1.** Write an Algo in english of how this can be done. **2.** Then look for *how to loop over Array of objects*, *how to manipulate array of objects*. **3.** Once done, try integrating them. When you face issue, share that attempt and we can help you – Rajesh Aug 27 '18 at 09:32
  • @Quentin People take arrow functions as *abra-ka-dabra*... :-p – Rajesh Aug 27 '18 at 09:33
  • I don't think this is the kind of problem that would be made easy with arrow functions. IMO, simplest and easiest is to first create an auxiliary mapping array which maps each id to the array entry and then loop again, sticking each array entry into the children via the mapping. – Willem M. Aug 27 '18 at 09:33

3 Answers3

0

It's hard to explain everything. I used recursion to search for a parent if it was already added to someone in the children.

let items = [
  {
    id: 1,
    is_child_question: false,
    parent_question_id: null 
  },
  {
    id: 2,
    is_child_question: true,
    parent_question_id: 1
  },
  {
    id: 3,
    is_child_question: true,
    parent_question_id: 2
  },
  {
    id: 4,
    is_child_question: true,
    parent_question_id: 1
  },
  {
    id: 5,
    is_child_question: true,
    parent_question_id: 2
  }
]
  
let result = []  
  
items.forEach(i => {
  if (!i.parent_question_id)
    result.push(i)
  else {
    let parent = findDeep(items, i.parent_question_id)
    if (!parent)
      return
    parent.children = parent.children || []
    parent.children.push(i)
  }
})

function findDeep (items, parentId) {
  const find = items.find(i => i.id === parentId)
  
  if (find)
    return find
  else {
    for (let item of items.filter(i => i.children)) {
      let result = findDeep(item.children, parentId)
      if (result)
        return result
    }
  }
  
  return null
}

console.log(result)
0

You could create recursive function using reduce method for this.

const data =  [{"id":1,"is_child_question":false,"parent_question_id":null},{"id":2,"is_child_question":true,"parent_question_id":1},{"id":3,"is_child_question":true,"parent_question_id":2},{"id":4,"is_child_question":false,"parent_question_id":2},{"id":5,"is_child_question":true,"parent_question_id":4},
{"id":6,"is_child_question":true,"parent_question_id":4}]

function tree(data, parentId = null) {
  return data.reduce((r, e) => {
    if (parentId == e.parent_question_id) {
      let elem = {...e}
      let children = tree(data, e.id);
      if (children.length) {
        if (!elem.children) {
          elem.children = []
        }

        children.forEach(c => {
          if (c.is_child_question) elem.children.push(c)
          else r.push({ ...c})
        })
      }
      r.push(elem)
    }
    return r;
  }, [])
}

const result = tree(data);
console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
0

You could take a single loop approach with an object for collecting objects with id as key.

var data = [{ id: 3, is_child_question: true, parent_question_id: 2 }, { id: 2, is_child_question: true, parent_question_id: 1 }, { id: 1, is_child_question: false, parent_question_id: null }],
    tree = data.reduce((r, o) => {
        o.children = r[o.id] && r[o.id].children;
        r[o.id] = o;
        r[o.parent_question_id] = r[o.parent_question_id] || {};
        r[o.parent_question_id].children = r[o.parent_question_id].children || [];
        r[o.parent_question_id].children.push(o);
        return r;
    }, {}).null.children;

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392