2

I have a set of data I'm collecting that outputs something like this:

[
    {
        hostName: 'server1',
        service: 'service1',
        perfData: 'unique string5',
        state: 1
    },
    {
        hostName: 'server1',
        service: 'service2',
        perfData: 'unique string4',
        state: 1
    },
    {
        hostName: 'server1',
        service: 'service3',
        perfData: 'unique string3',
        state: 1
    },
    {
        hostName: 'server2',
        service: 'service1',
        perfData: 'unique string2',
        state: 1
    },
    {
        hostName: 'server2',
        service: 'service2',
        perfData: 'unique string1',
        state: 1
    }
]

I'm trying to loop through this array of objects with javascript to output the following:

let desiredOutput = [{'server1': [{
        service: 'service1',
        perfData: 'unique string1',
        state: 1
        },
        {
        service: 'service2',
        perfData: 'unique string1',
        state: 1
        },
        {
        service: 'service3',
        perfData: 'unique string1',
        state: 1
        }],
    'server2': {
        service: 'service1',
        perfData: 'unique string1',
        state: 1
    }
}];

Does Javascript have something similar to dict comprehension? Not sure how to loop through an array of objects and merge them and make them an object with an array of objects. In python I could use something like this:

raw_data = [{'hostName': 'server1', 'serviceName': 'service1'}, {'hostName': 'server1', 'serviceName': 'service2'}, {'hostName': 'server1', 'serviceName': 'service3'}, {'hostName': 'server2', 'serviceName': 'service1'}, {'hostName': 'server2', 'serviceName': 'service2'}]
services = defaultdict(list)
for service in raw_data:
    host_name = service.get('hostName')
    service_name = service.get('service')
    new_dict = {'hostName': host_name, 'serviceName': service_name}
    services[new_dict['hostName']].append(new_dict)
print(services)

I found something close with this Merge javascript objects in array with same key but not quite what I'm looking for.

Ian Clark
  • 77
  • 1
  • 8
  • JavaScript has several built in `Array.prototype` methods for traverse and transforming arrays. More information can be found at the MDN for Arrays https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array – Robert Mennell Nov 20 '18 at 21:16
  • Also in JavaScript we just access them using the bracket notation: `object[key]` or `object.key` if the key is known. As for making a new object, object literals are allowed to use computed values `{ [key] : value }` and more information can be found here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015 – Robert Mennell Nov 20 '18 at 21:20
  • 1
    The Python code you posted does not have a "dict comprehension". You are iterating in a conventional `for` loop and then building your `services` dictionary. With Javascript, the most appropriate array method for this case seems like `reduce`. – slider Nov 20 '18 at 21:22
  • 1
    I don't see how this relates to dict comprehension as your Python snippet does not use it. Python dict comprehension looks like `{ key: value for key, value in iterable }` – trincot Nov 20 '18 at 21:23
  • Shouldn't your result include `{"service": "service2", "perfData": "unique string1", "state": 1}` in the `server2` key? – ggorlen Nov 20 '18 at 21:28

1 Answers1

0

Your output structure is a bit strange (an array of one element?). Using reduce is a reasonable approach, building arrays for each unique key:

const data = [ { hostName: 'server1', service: 'service1', perfData: 'unique string5', state: 1 }, { hostName: 'server1', service: 'service2', perfData: 'unique string4', state: 1 }, { hostName: 'server1', service: 'service3', perfData: 'unique string3', state: 1 }, { hostName: 'server2', service: 'service1', perfData: 'unique string2', state: 1 }, { hostName: 'server2', service: 'service2', perfData: 'unique string1', state: 1 } ];

console.log([data.reduce((a, e) => {
  const name = e.hostName;
  delete e.hostName;
  a[name] = name in a ? a[name].push(e) && a[name] : [e];
  return a;
}, {})]);
ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • why not `a[name] = name in a ? [...a[name], e] : [e];` if you want to make concatenation smaller, or use `a[name] = name in a ? a[name].push(e) && a[name] : [e];` so that you can avoid the complexity problem your example introduces? – Robert Mennell Nov 20 '18 at 21:23
  • All three options seem more or less the same complexity level to my mind, but thanks for the alternatives. – ggorlen Nov 20 '18 at 21:26
  • `[...a[name], e]` will create a new array, traverse the original, then push the new element. `a[name].concat([e])` will create a new array by traversing the first to copy it, and then traverse the second to push(most complex). `a[name].push(e) && a[name]` will push onto the array and then return it(least complex). All three have slightly different complexity – Robert Mennell Nov 20 '18 at 21:46
  • 1
    Oh, you're talking about time complexity/efficiency--I thought you were talking readability. That's fair enough. – ggorlen Nov 20 '18 at 21:52