Reputation: 2396
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
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
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
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