-1

I have an array of parent objects with nested array of children in a structure like so:

[
  {
    "fullName": "Certificate",
    "checked": false,
    "children": [
      {
        "type": "Certificate",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Certificate-1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package2",
      }
    ]
  },
  {
    "fullName": "Network",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Network1",
      }
    ]
  }
]

I would like to merge any parent nodes with the same 'fullName' while pushing the children together. The desired output is:

[
  {
    "fullName": "Certificate",
    "checked": false,
    "children": [
      {
        "type": "Certificate",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Certificate-1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package1",
      },
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package2",
      }
    ]
  },
  {
    "fullName": "Network",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Network1",
      }
    ]
  }
]

Is there an elegant way of achieving this (with lodash or other)? I have tried a number of looping solutions based on answers found here but I haven't been able to get it quite right. Any ideas?

@Andy, most of the code I have tried has been based on the answers found in the hyperlink, one attempt that looked promising was:

function mergeNames (arr) {
    return _.chain(arr).groupBy('fullName').mapValues(function (v) {
        return _.chain(v).map('fullName').flattenDeep();
    }).value();
}

console.log(mergeNames(array));

But the output of this is a "lodash wrapper"? and doesn't quite correctly push the children together - I think perhaps because I have the same identifier (fullName) at both the child and parent level? When I run this code and copy the output from chrom console, i get the following:

{
  "Certificate": [
    "Certificate"
  ],
  "InstalledPackage": [
    "InstalledPackage",
    "InstalledPackage"
  ],
  "Network": [
    "Network"
  ]
}
nom
  • 95
  • 2
  • 9
  • You need to add the code you've attempted so we can look at it, not expect us to write something from scratch for you. – Andy Sep 06 '17 at 13:49
  • And you should point to the section that should be merged. I had to look twice before I saw the difference between the two code blocks. – iquellis Sep 06 '17 at 13:50
  • Apologies, I've added some highlighting to the sections that should be merged. – nom Sep 06 '17 at 13:53

3 Answers3

1

You can do this using Array.prototype methods like this:

let data = [
  {
    "fullName": "Certificate",
    "checked": false,
    "children": [
      {
        "type": "Certificate",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Certificate-1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package2",
      }
    ]
  },
  {
    "fullName": "Network",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Network1",
      }
    ]
  }
];

let result = data.reduce((res, elem) => {
 let arrForChecking = res.filter((el) => el.fullName === elem.fullName);

 if (arrForChecking.length) {
  arrForChecking[0].children.push(elem.children[0]);

  return res;
 }

 return res = res.concat(elem);
}, []);

console.log(result);
Ivan Minakov
  • 1,432
  • 7
  • 12
  • Thanks Ivan, this produced exactly what I was after. I'm new to this so thanks for showing me how the reduce function works! – nom Sep 06 '17 at 14:20
0

You could define the keys for combined grouping on and use a hash table for the groups while pushing single groups to the result array.

var array = [{ fullName: "Certificate", checked: false, children: [{ type: "Certificate", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Certificate-1" }] }, { fullName: "InstalledPackage", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Package1" }] }, { fullName: "InstalledPackage", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Package2" }] }, { fullName: "Network", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Network1" }] }],
    hash = Object.create(null),
    keys = ['fullName', 'checked'],
    grouped = [];

array.forEach(function (o) {
    var key = keys.map(function (k) { return o[k]; }).join('|');
    if (!hash[key]) {
        hash[key] = {};
        keys.forEach(function (k) { hash[key][k] = o[k]; });
        hash[key].children = [];
        grouped.push(hash[key]);
    }
    hash[key].children = hash[key].children.concat(o.children);
});

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

ES6

var array = [{ fullName: "Certificate", checked: false, children: [{ type: "Certificate", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Certificate-1" }] }, { fullName: "InstalledPackage", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Package1" }] }, { fullName: "InstalledPackage", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Package2" }] }, { fullName: "Network", checked: false, children: [{ type: "InstalledPackage", lastModifiedDate: "1971-01-01T00:00:00.000Z", fullName: "Network1" }] }],
    hash = Object.create(null),
    keys = ['fullName', 'checked'],
    grouped = [];

array.forEach(function (o) {
    var key = keys.map(k => o[k]).join('|');
    if (!hash[key]) {
        hash[key] = Object.assign({}, o);
        grouped.push(hash[key]);
        return;
    }
    hash[key].children.push(...o.children);
});

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

here you go

as = [
  {
    "fullName": "Certificate",
    "checked": false,
    "children": [
      {
        "type": "Certificate",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Certificate-1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package1",
      }
    ]
  },
  {
    "fullName": "InstalledPackage",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Package2",
      }
    ]
  },
  {
    "fullName": "Network",
    "checked": false,
    "children": [
      {
        "type": "InstalledPackage",
        "lastModifiedDate": "1971-01-01T00:00:00.000Z",
        "fullName": "Network1",
      }
    ]
  }
]

ad = []
i=-1
as.forEach(function(item, index){
  if(index>0){
    i=i+1
    if(as[index]['fullName'] === as[i]['fullName']) {
      item['children'] = item['children'].concat(as[i]['children'])
      ad[ad.length - 1] = item
    } else {
      ad.push(item)
    }
  } else {
    ad.push(item)
  }
})
cahyowhy
  • 553
  • 2
  • 9
  • 26