0

I'd like to create a tree of services from a string which are properties of people. I manage to do it, but the code is quite ugly, and it's a king of practice for me for the trick is i'd like to make it with "class" of objects using "Object.create()" where the class would look like this :

let service = {
        serviceFather: "",
        serviceChildren: [],
        people: [],
        }
    }; 

A sample of input is :

[
  {
    "name": "John Doe",
    "service": "EE",
  },
  {
    "name": "Jane Doe",
    "service": "EE.EA",
  },
  {
    "name": "Jack Smith",
    "service": "EE.EA.EB",
  },
  {
    "name": "Jill Smith",
    "service": "EE.EA.EC"
  },
  {
    "name": "Jake Smith",
    "serviceLevel": "EE.EA.EC"
  }
]

The expected output would be :

[
{
    "name": "EE",
    "serviceFather": "root",
    "people": [
    {
        "name": "John Doe"
    }],
    "serviceChildren": [
    {
        "name": "EA",
        "serviceFather": "EE",
        "people": [
        {
            "name": "Jane Doe"
        }],
        "serviceChildren": [
        {
            "name": "EB",
            "serviceFather": "EA",
            "people": [
            {
                "name": "Jack Smith"
            }],
            "sousService": ""
        },
        {
            "name": "EC",
            "serviceFather": "EA",
            "people": [
            {
                "name": "Jill Smith"
            },
            {
                "name": "Jake Smith"
            }],
            "sousService": ""
        }]
    }]
}]
CoStiC
  • 85
  • 8
  • 3
    please add your try and what goes wrong. btw `service` !== `serviceLevel` as key. – Nina Scholz Mar 21 '19 at 10:45
  • 1
    `The expected output would be` why? whats the logic? – Jaromanda X Mar 21 '19 at 10:47
  • @JaromandaX : the goal is to make a tree of services... the expected output looks like a tree of services. What is not logical ? – CoStiC Mar 21 '19 at 10:57
  • Can you have more than one `service: "EE"` ... can you have more than one root level service, e.g. `service: "FF"`? if so, is it valid to have an `EE.EA` and an `FF.EA` for example? and finally, have you written a single line of code yourself? – Jaromanda X Mar 21 '19 at 11:00
  • @NinaScholz my try has not made anythink near the goal. The thing is i don't really get how i can check the existence of an object created this way. for example : let services = obj.service.split("."); for (let i = 0; i < obj.services.length); i++) {if (this.name !== services[i]) {let newService = Object.create(service)} else {????}} – CoStiC Mar 21 '19 at 11:02
  • @JaromandaX OK!!! i understand what you meant! Sorry : EE is the father of all services. And it will always have the index 0 in the array. the change will start at index1 where we will be able to have more than one children service. I tried many ways but none of it is near the result I expected. I dont even get the way to check the existance of the father object – CoStiC Mar 21 '19 at 11:11
  • in this sample, EE is always the father, but i'd like to make it possible to have more than EE service (in case the organization would change) – CoStiC Mar 21 '19 at 11:17
  • Uh, I see no reason to use `Object.create` here. Just use a plain object literal. – Bergi Mar 21 '19 at 11:17
  • @Bergi because i d like to understand the use of "object.create" and i d like to make it possible to reuse it when there s more than 1 root (here EE) – CoStiC Mar 21 '19 at 11:19
  • What do you mean by "reuse"? And what do expect the objects to inherit from? Your desired output shows plain objects only. `Object.create` should only be used if you need objects with custom prototypes. – Bergi Mar 21 '19 at 11:30

2 Answers2

1

You could use split on service property and then forEach loop and reduce to iterate nested tree and add to array.

const data = [{ "name": "John Doe", "service": "EE" }, { "name": "Jane Doe", "service": "EE.EA" }, { "name": "Jack Smith", "service": "EE.EA.EB" },
  { "name": "Jill Smith", "service": "EE.EA.EC" }, { "name": "Jake Smith", "service": "EE.EA.EC" }
]

let service = {
  serviceFather: "",
  serviceChildren: [],
  people: [],
};

function create(data) {
  const res = []
  data.forEach(obj => {
    obj.service.split('.').reduce((r, e, i, a) => {
      const match = r.find(({ name }) => name == e);
      if(!match) {
        const o = Object.create(service);
        o.name = e;
        o.serviceFather = (i == 0 ? 'root' : a[i - 1])
        o.people = [{ name: obj.name }]
        o.serviceChildren = [];
        r.push(o)
        return r;
      } else {
        if(!a[i + 1]) match.people.push({ name: obj.name })
        return match.serviceChildren
      }
    }, res)
  })
  return res;
}

const result = create(data)
console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • damn! sure... simplest things are mostly often the best ones!!! thank you! – CoStiC Mar 21 '19 at 12:48
  • smthg went wrong. there s 2 divisions in which some grand children have the same "name" in each division. So the grand children of the second division went to the the first division... i think we should take another property to build the tree. – CoStiC Mar 27 '19 at 08:30
  • A right https://stackoverflow.com/questions/55697226/create-an-tree-of-objects-from-arrays – Jonas Wilms Apr 16 '19 at 10:17
1

You could take a dummy object and iterate the service levels.

var data = [{ name: "John Doe", service: "EE" }, { name: "Jane Doe", service: "EE.EA" }, { name: "Jack Smith", service: "EE.EA.EB" }, { name: "Jill Smith", service: "EE.EA.EC" }, { name: "Jake Smith", service: "EE.EA.EC" }],
    result = [];

data.forEach(({ name, service }) => {
    service
        .split('.')
        .reduce((o, k, i, a) => {
            var temp = (o.serviceChildren = o.serviceChildren || []).find(({ name }) => name === k);
            if (!temp) {
                o.serviceChildren.push(temp = {
                    name: k,
                    serviceFather: a[i - 1] || 'root',
                    people: []
                });
            }
            return temp;
        }, { serviceChildren: result })
        .people.push({ name });
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Thank you. This is a way to solve it, even if i was looking for the way to use "classes". :) – CoStiC Mar 21 '19 at 12:56