Kracki
Kracki

Reputation: 63

javascript convert into parent-child array

Can anyone help converting the following list of parent-child objects:

I have below array of objects, Need to convert it into parent child order. each 'Members' attribute in object may have 1 or n objects inside it. In 'Members' array the 1st object is parent of 2nd one and 2nd is parent of third object.

So in 1st Member 'Video' is parent of 'West' and 'West' is parent of 'India' and so on..

I have tried to loop through the elements one by one but could not reach the desired outcome.

Any help with the logic or code would be really helpful.

Input :

[
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Machinery"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Electronics"
      },
      {
        "Name": "Midwest"
      },
      {
        "Name": "Arab"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Machinery"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Electronics"
      },
      {
        "Name": "NorthEast"
      },
      {
        "Name": "Japan"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "Japan"
      }
    ]
  }
]

Expected Output :

[
  {
    "name": "Videos",
    "children": [
      {
        "name": "West",
        "children": [
          {
            "name": "India",
            "children": []
          },
          {
            "name": "Japan",
            "children": []
          }
        ]
      },
      {
        "name": "South",
        "children": [
          {
            "name": "Australia",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Machinery",
    "children": [
      {
        "name": "South",
        "children": [
          {
            "name": "Australia",
            "children": []
          }
        ]
      },
      {
        "name": "West",
        "children": [
          {
            "name": "India",
            "children": []
          }
        ]
      }
    ]
  },
  {
    "name": "Electronics",
    "children": [
      {
        "name": "Midwest",
        "children": [
          {
            "name": "Arab",
            "children": []
          }
        ]
      },
      {
        "name": "NorthEast",
        "children": [
          {
            "name": "Japan",
            "children": []
          }
        ]
      }
    ]
  }
]

```

Upvotes: 0

Views: 1314

Answers (3)

Kobe
Kobe

Reputation: 6446

Man this took too long. But it works with larger datasets. Note to OP, never use this data structure. Ever. It's horrible. I lost many braincells making this solution:

var arr = [
  {Members: [{ Name: "Videos" }, { Name: "West" }, { Name: "India" }, {Name: 'Testing'}]},
  {Members: [{ Name: "Machinery" }, { Name: "South" }, { Name: "Australia" }]},
  {Members: [{ Name: "Electronics" }, { Name: "Midwest" }, { Name: "Arab" }]},
  {Members: [{ Name: "Machinery" }, { Name: "West" }, { Name: "India" }]},
  {Members: [{ Name: "Electronics" }, { Name: "NorthEast" }, { Name: "Japan" }]},
  {Members: [{ Name: "Videos" }, { Name: "South" }, { Name: "Australia" }]},
  {Members: [{ Name: "Videos" }, { Name: "West" }, { Name: "Japan" }]}
];

const addRelation = (obj, m, i) => ({...obj, parent: i === 0 ? null : m.slice(0, i).map(el => el.Name).join('.'), level: i, children: []})

const arrayToTree = (arr) => {
    arr = arr.map(({ Members: m }) => m.map((obj, i) => addRelation(obj, m, i))).reduce((acc, arr) => {
        arr.map(obj => acc.push(obj))
        return acc
    }, []).sort((a, b) => b.level - a.level)    
    
    var temp = [...arr].filter((o, index, self) =>
        index === self.findIndex((t) => (
            t.Name === o.Name && t.parent === o.parent
        ))
    )

    arr.forEach(() => {
        if (temp[0].level === 0) return
        var parentIndex = temp.findIndex(o => {
            var str = temp[0].parent
            var rest = str.substring(0, str.lastIndexOf("."));
            var last = str.substring(str.lastIndexOf(".") + 1, str.length);
            var parents = [rest, last]
            return parents[0] !== ''
              ? o.Name === parents[1] && o.parent === parents[0]
              : o.Name === temp[0].parent
        })
        const { Name, children } = temp[0]
        temp[parentIndex].children.push({Name, children})
        temp.shift()
    })
        
    return temp.map(({ Name, children }) => ({ Name, children }))
}

arr = arrayToTree(arr)
console.log(arr)

Upvotes: 3

dganenco
dganenco

Reputation: 1616

I would advise to use map + reduce combination:

const data = [{
    "Members": [{
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Machinery"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Electronics"
      },
      {
        "Name": "Midwest"
      },
      {
        "Name": "Arab"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Machinery"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Electronics"
      },
      {
        "Name": "NorthEast"
      },
      {
        "Name": "Japan"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Videos"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [{
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "Japan"
      }
    ]
  }
];

const ar = data.map((el, i) => {
  let a = el['Members'].reduce((acc, member, index) => {
    if (index === 0) {
      acc[index] = {
        name: member.Name,
        children: []
      };
    } else {
      debugger;
      if (acc[0].children.length === 0) {
        acc[0].children.push({
          name: member.Name,
          children: []
        });
      } else {
        acc[0].children[0].children.push({
          name: member.Name,
          children: []
        });
      }
    }

    return acc;
  }, []);

  return a;
});

console.log(ar);

Upvotes: -1

Andam
Andam

Reputation: 2167

This might not be the best way to go about this and this only works for 3 levels.

var data = [
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Machinery"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Electronics"
      },
      {
        "Name": "Midwest"
      },
      {
        "Name": "Arab"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Machinery"
      },
      {
        "Name": "West"
      },
      {
        "Name": "India"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Electronics"
      },
      {
        "Name": "NorthEast"
      },
      {
        "Name": "Japan"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "South"
      },
      {
        "Name": "Australia"
      }
    ]
  },
  {
    "Members": [
      {
        "Name": "Videos"
      },
      {
        "Name": "West"
      },
      {
        "Name": "Japan"
      }
    ]
  }
];


function organize(dataBefore){
  var dataAfter = [];
  
 dataAfter.push({
    name: dataBefore[0].Members[0].Name,
    children: []
  });
    
  for(var i = 1; i < dataBefore.length; i++){
    if(!doesExist(dataAfter, dataBefore[i].Members[0].Name)){
      dataAfter.push({
        name: dataBefore[i].Members[0].Name,
        children: []
      });
    }
  }

  dataAfter[0].children.push({
    name: dataBefore[0].Members[1].Name,
    children: []
  });

  for(var i = 1; i < dataBefore.length; i++){
      for(var j = 0; j < dataAfter.length; j++){
          if(dataAfter[j].name == dataBefore[i].Members[0].Name){
            if(!doesExist(dataAfter[j].children, dataBefore[i].Members[1].Name)){
                dataAfter[j].children.push({
                    name: dataBefore[i].Members[1].Name,
                    children: []
                });
            }
          }
      }
  }

  dataAfter[0].children[0].children.push({
    name: dataBefore[0].Members[2].Name,
    children: []
  });

  for(var i = 1; i < dataBefore.length; i++){
      for(var j = 0; j < dataAfter.length; j++){
        if(dataAfter[j].name == dataBefore[i].Members[0].Name){
            for(var k = 0; k < dataAfter[j].children.length; k++){
                if(dataAfter[j].children[k].name == dataBefore[i].Members[1].Name){
                    if(!doesExist(dataAfter[j].children[k].children, dataBefore[i].Members[2].Name)){
                        dataAfter[j].children[k].children.push({
                            name: dataBefore[i].Members[2].Name,
                            children: []
                        });
                    }
                }
            }
        }
      }
  }

  return dataAfter;
}

function doesExist(checkThisData, searchValue){
    for(var i = 0; i < checkThisData.length; i++){
        if(searchValue == checkThisData[i].name){
            return true;
        }
    }
  
    return false;
}

console.log(organize(data));

Upvotes: 1

Related Questions