2

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?

0

3 Answers 3

3

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));

Sign up to request clarification or add additional context in comments.

1 Comment

for completeness sake, since I intended to use map.forEach(), I used let output = new Map() instead of let output = {}; which allows me to use forEach() comfortably
1

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"
    }
  ]
}

Comments

1

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);

2 Comments

I don't quite understand your code, There is an unused variable newarray, your are trying to access a string key in a array, whose keys are numbers. And you are suggesting JQuery when there was not mention of that library in OP's question. I don't want to be rude, i just feel like your answer could use some improvement.
I have updated the code. Sorry pasted the wrong one

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.