shimmiChristo
shimmiChristo

Reputation: 33

How to consolidate an array of objects

I have an array of objects and I am trying to consolidate the objects. I am trying to create a function that takes in the list as an argument and returns the new object.

function mergeValues(list) {
    var obj = {};
    list.forEach(item => {
        if (!obj[item.state]) {
            obj[item.state] = Object.assign({}, Object.keys(obj));
        } else {
            obj[item.state] = obj[item.state] + item.population;
        }
    });
    return obj;
}

Current Input

var list = [
  { state: 'NJ', city: 'Newark', population: 150 },
  { state: 'NJ', city: 'Trenton', population: 200 },
  { state: 'NY', city: 'New York City', population: 500 },
  { state: 'MI', city: 'Detroit', population: 200 },
  { state: 'MI', city: 'Lansing', population: 100 }
];

Desired Output

var obj = {
  MI: { count: 2, city: ['Detroit', 'Lansing'], population: 300 },
  NJ: { count: 2, city: ['Newark', 'Trenton'], population: 350 },
  NY: { count: 1, city: ['New York City'], population: 500 }
};

Edit: This is how I started, and am getting stuck. The key is returned with the state, but the values are being overridden with the most recent object.

function mergeValues(list) {
  var obj = {};

  list.forEach(item => {
    obj[item.state] = Object.assign({}, item);
  });

  return obj;
}

Upvotes: 1

Views: 394

Answers (2)

Mart
Mart

Reputation: 311

With reduce its quit easy.

function transform(list) {
    return list.reduce((latestState, { state, city, population }) => {
        const isNewEntry = !(state in latestState);
        if(isNewEntry){
            latestState[state] = {
                count: 1,
                city: [city],
                population: population
            }
        }else{
            latestState[state] = {
                count: latestState[state].count + 1,
                city: [...latestState[state].city, city],
                population: latestState[state].population + population
            }
        }
        return latestState;
    }, {});
}

So whats going on here.

With reduce we loop over the list and every new loop we receive the latest state, in this example we start with a empty object.

Next, we check if entry needs creation or a update (exists). Based on isNewEntry we create or update the entry.

https://codesandbox.io/s/amazing-ellis-mh4b6

Upvotes: 2

trincot
trincot

Reputation: 350137

You could use Object.fromEntries to create the state/object mapping, and then iterate the original list to aggregate the count, city and population:

function mergeValues(list) {
    let obj = Object.fromEntries(list.map(({state}) => 
                  [state, { count: 0, city: [], population: 0 }]
    ));
    list.forEach(({state, city, population}) => {
        obj[state].count++;
        obj[state].city.push(city);
        obj[state].population += population; 
    });
    return obj;
}

var list = [{ state: 'NJ', city: 'Newark', population: 150 },{ state: 'NJ', city: 'Trenton', population: 200 },{ state: 'NY', city: 'New York City', population: 500 },{ state: 'MI', city: 'Detroit', population: 200 },{ state: 'MI', city: 'Lansing', population: 100 }];
console.log(mergeValues(list));

Upvotes: 1

Related Questions