1

I have a flat array like this, I'm supposed to build a flat array for it. The object will be an children property of it's parent object if the pid is not null. How should I do this?

    var a = [
        {id: 1, pid: null}, 
        {id: 2, pid: 1}, 
        {id: 3, pid: 1}, 
        {id: 4, pid: 3}, 
        {id: 5, pid: 3}
     ];

Expect output:

     var result = [{id: 1, children: [
        {id: 2, children: []},
        {id: 3, children: [{id: 4}, {id: 5}]}
    ]}]
1

4 Answers 4

2

You could use a single loop approach which works for unsorted arrays as well.

var a = [{ id: 1, pid: null }, { id: 2, pid: 1 }, { id: 3, pid: 1 }, { id: 4, pid: 3 }, { id: 5, pid: 3 }],
    tree = function (data, root) {
        return data.reduce(function (o, { id, pid }) {
            o[id] = o[id] || { id };
            o[pid] = o[pid] || { id: pid };
            o[pid].children = o[pid].children || [];
            o[pid].children.push(o[id]);
            return o;
        }, {})[root].children;
    }(a, null);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to get not whole tree but a specifc child tree? getChildTree(array,id)?
@rendom, you could take the parent of the wanted id instead of null for the tree.
Is there way to convert tree back to list?
@rendom, yes it is possible by traversing the tree and handing over the parent.
1

You could use reduce() method and create recursive function.

var a = [{id: 1, pid: null}, {id: 2, pid: 1}, {id: 3, pid: 1}, {id: 4, pid: 3}, {id: 5, pid: 3}];

function tree(data, parent) {
  return data.reduce((r, {id,pid}) => {
    if (parent == pid) {
      const obj = {id}
      const children = tree(data, id);
      if (children.length) obj.children = children;
      r.push(obj)
    }
    return r;
  }, [])
}

const result = tree(a, null);
console.log(result);

3 Comments

Thanks. But I'm wondering what could I do if I want my output exactly like" var result =..........". I mean, starts with "var result ="
Not sure what you are asking.
now the output of your method is an array tree. what if I want something format like" var result =.....(the array tree goes here)".
0

Both answers using reduce here are great, one slight issue is that there both multi-pass, IOW: if the tree was very big there is going to be a lot of linear searching.

One solution to this is to first build a map, and then flatten the map.. mmm, actually flatten is probably the wrong word here, maybe expand.. :) But you get the idea..

Below is an example.

const a = [
    {id: 1, pid: null}, 
    {id: 2, pid: 1}, 
    {id: 3, pid: 1}, 
    {id: 4, pid: 3}, 
    {id: 5, pid: 3}
 ];
 
 
function flatern(map, parent) {
  const g = map.get(parent);
  const ret = [];
  if (g) {
    for (const id of g) {
      const k = {id};
      ret.push(k);
      const sub = flatern(map, id);
      if (sub) k.children = sub;
    }
    return ret;
  }
  return null;
}
     
function tree(a) {
  const m = new Map();
  a.forEach((i) => {
    const g = m.get(i.pid);
    if (!g) {
      m.set(i.pid, [i.id]);
    } else {
      g.push(i.id);
    }
  });
  return flatern(m, null);
}

console.log(tree(a));
.as-console-wrapper { max-height: 100% !important; top: 0; }

4 Comments

btw, my approach uses an object where no search takes place, because of hash table. access is O(1).
@NinaScholz Nice one, must admit didn't really examine code in detail.. Your's look easier than mine so, I'm up-voting yours.. I'll keep mine here for those who find it easier to read / understand.
Hi thanks a lot. But I have a difficult time understanding what it means by"if (sub) k.children = sub;", could you explain why there is a () on sub?
It just means if there are any sub items, and them as children.
0
    var a = [
        {id: 1, pid: null}, 
        {id: 2, pid: 1}, 
        {id: 3, pid: 1}, 
        {id: 4, pid: 3}, 
        {id: 5, pid: 3}
    ];

    function processToTree(data) {
        const map = {};
        data.forEach(item => {
            map[item.id] = item;
            item.children = [];
        });

        const roots = [];
        data.forEach(item => {
            const parent = map[item.pid];
            if (parent) {
                parent.children.push(item);
            }
            else {
                roots.push(item);
            }
        });
        return roots;
    }

Learnt this method today, I think this is the best

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.