CybeX
CybeX

Reputation: 2396

javascript - reduce array of objects to a key value pair map retaining duplicate entries in a value array

I need to reduce an array of objects, but reduce on a specific key property in the object, and have all objects with the same key value placed into an array in the associated value array.

An example of what I need:

Objects

var obj1 = {
  name: "server1",
  type: "http",
  port: "8080"
}

var obj2 = {
  name: "server2",
  type: "https",
  port: "8443"
}

var obj3 = {
  name: "server3",
  type: "http",
  port: "80"
}

// Place objects in an array (as interm step)
var array = [obj1, obj2, obj3];

With the above code, I tried

var map = new Map(array.map(server => [server.type, server]));

but this ends up giving me:

0: {"http" => Object}
    key: "http"
    value:
        name: "server3"
        port: "80"
        type: "http"
1: {"https" => Object}
    key: "https"
    value:
        name: "server2"
        port: "8443"
        type: "https"

but what I need is:

0: {"http" => Object}
    key: "http"
    value:[ 
        {
            name: "server1"
            port: "8080"
            type: "http"
        },
        {
            name: "server3"
            port: "80"
            type: "http"
        },
1: {"https" => Object}
    key: "https"
    value:
        name: "server2"
        port: "8443"
        type: "https"

So I can go through each type, find all unique values, create lists of each object with this as a type, then add this to a map but it seems too much for a simple task.

Is there a faster/more convenient way to shorten this?

Upvotes: 2

Views: 4596

Answers (3)

Amit Sharma
Amit Sharma

Reputation: 1795

I think this is how you can achieve it

var array = [obj1, obj2, obj3];
var newarray = [];
$.each(array, function( index, value ) {

 if(!newarray[value.type]) {
   newarray[value.type] = {data:[]};
 }
 newarray[value.type].data.push(value);
});

console.log(newarray);

Upvotes: 1

Ivan Kahl
Ivan Kahl

Reputation: 618

This is the perfect use-case for reduce(). The format is:

arr.reduce(callback( accumulator, currentValue[, index[, array]] )[, initialValue])

We would set our initialValue argument to an empty object ({}). Our callback function will then take each item in the array and add it to the correct array in our categorised object. See below:

var obj1 = {
  name: "server1",
  type: "http",
  port: "8080"
}

var obj2 = {
  name: "server2",
  type: "https",
  port: "8443"
}

var obj3 = {
  name: "server3",
  type: "http",
  port: "80"
}

// Place objects in an array (as interm step)
var array = [obj1, obj2, obj3];

const result = array.reduce((categorisedObjs, currentItem) => {
  // If the key does not yet exist in our object then create it
  // and initialize it with an empty array
  if (!categorisedObjs[currentItem.type]) categorisedObjs[currentItem.type] = []

  // Add the object to the correct array
  categorisedObjs[currentItem.type].push(currentItem);

  // Return the categorised objects for the next iteration
  return categorisedObjs;
}, {});

console.log(JSON.stringify(result, true, 2));

This will produce the exact result desired and it's relatively simple to understand:

{
  "http": [
    {
      "name": "server1",
      "type": "http",
      "port": "8080"
    },
    {
      "name": "server3",
      "type": "http",
      "port": "80"
    }
  ],
  "https": [
    {
      "name": "server2",
      "type": "https",
      "port": "8443"
    }
  ]
}

Upvotes: 1

Nicolas
Nicolas

Reputation: 8670

I'm not sure a map would be an appropriate function here. You could use a simple forEach and check if the current key already exists in your array. If it doesn't, you create a new object with the current item and check the next one.

Something like this:

var obj1 = {
  name: "server1",
  type: "http",
  port: "8080"
}

var obj2 = {
  name: "server2",
  type: "https",
  port: "8443"
}

var obj3 = {
  name: "server3",
  type: "http",
  port: "80"
}

// Place objects in an array (as interm step)
var array = [obj1, obj2, obj3];

let output = {};
array.forEach((item) => {
  // the item does not exists, we create it.
  if(!output[item.type]) {
    output[item.type] = {key: item.type, value: []};
  }
  // in either case, we push the current item in the value.
  // of the current output key.
  output[item.type].value.push(item);
});

// we are using Object.values() because we do not want the keys
// used to generate the output.
console.log(Object.values(output));

Upvotes: 3

Related Questions