1

Given the following collection, what would be the best way to consolidate this data to group by room and make the "names" an array; excluding duplicates, and do not want to use the call the key "name" to make it more dynamic if there are more fields:

var roomAssignments = [{
    room: 'Foo',
    name: 'Fooname',
    other: 'Other'
},{
    room: 'Bar',
    name: 'Barname',,
    other: 'OtherBar'
},{
    room: 'Foo',
    name: 'Baz',,
    other: 'Other'
},{
    room: 'Foo',
    name: 'Baz',,
    other: 'Other'
},{
    room: 'Foo',
    name: 'Bat',,
    other: 'Other'
}];

Desired output:

[{
    room: 'Foo',
    name: [ 'Fooname', 'Baz', 'Bat' ],
    other: ['Other']
}, {
    room: 'Bar',
    name: [ 'Barname' ],
    other: ['OtherBar']
}]

I'm using lodash currently and would prefer that or plain javascript. I think I've been looking at this too long and what I have has about 30 keys that need to be combined into arrays, and I'm looking for the most efficient way to combine all keys into arrays dynamically.

harryBundles
  • 150
  • 3
  • 15

2 Answers2

1

You can use the function reduce and the function includes to discard duplicate values.

var roomAssignments = [{    room: 'Foo',    name: 'Fooname',    other: 'Other'},{    room: 'Bar',    name: 'Barname',    other: 'OtherBar'},{    room: 'Foo',    name: 'Baz',    other: 'Other'},{    room: 'Foo',    name: 'Baz',    other: 'Other'},{    room: 'Foo',    name: 'Bat',    other: 'Other'}],
    result = Object.values(roomAssignments.reduce(function(a, c) {
  if (a[c.room]) {
    Object.keys(c).forEach(function(k) {
      if (k === 'room') return;      
      if (a[c.room][k]) {
        if (!a[c.room][k].includes(c[k])) a[c.room][k].push(c[k]);
      } else a[c.room][k] = [c[k]];
    });
  } else { 
    a[c.room] = { room: c.room };
    Object.keys(c).forEach(function(k) {
      if (k === 'room') return;      
      a[c.room][k] = [c[k]];
    });
  }
  
  return a
}, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75
  • How would you reduce each key without actually calling it out? I'd prefer to not use the "name" and group all keys that may be in the object. – harryBundles Mar 09 '18 at 12:35
  • "message": "SyntaxError: invalid property id", "filename": "https://stacksnippets.net/js", "lineno": 26, "colno": 33 } – harryBundles Mar 09 '18 at 14:05
  • @harryBundles that error is not related to my code snippet. Try to run it in another browser. – Ele Mar 09 '18 at 14:06
  • Well, unfortunately I'm working in an intranet environment where my browsers are mostly outdated. While I appreciate the modern approach, I'm forced to keep it ES6 to support older browsers. – harryBundles Mar 09 '18 at 14:26
  • I updated the code to use lodash to replace the ES7 stuff that didn't work in my lowest supported browser. Thanks for helping me with this! – harryBundles Mar 09 '18 at 18:10
0

"Efficient" is kind of subjective. The following code is fairly efficient but, more importantly, it's nicer to look at.

var rooms = {};
roomAssignments.forEach(assignment => {
    var title = assignment.room;

    // grab existing room from our rooms map
    // if it doesn't exist, create it
    var room = rooms[title] || (rooms[title] = {room: title});

    for(var k in assignment){

      // skip the room key (it's our room title)
      if(k === 'room') continue;

      var value = assignment[k];

      // grab the existing field from the room object
      // if it doesn't exist, create it
      var field = room[k] || (room[k] = []);

      // see if the value already exists
      // if not, push it
      if(field.indexOf(value) === -1) field.push(value);
    }
})
THEtheChad
  • 2,372
  • 1
  • 16
  • 20