Home > Software engineering >  Loop through an array of objects, find duplicate objects by id, add their values in a single object,
Loop through an array of objects, find duplicate objects by id, add their values in a single object,

Time:05-12

I have a function inside of a react class component which generates properties. Since I want to be able to have duplicate properties, I've done it in a way that it is possible. However, I want those duplicate properties to be combined as a single value so that it can be displayed in the render function as a single property with a bigger value instead of 2 properties with smaller values. How can I achieve this based on the below code?

changePropertyState = () => {
  let rngProperties = []

  let maxProp = this.state.rarity.maxProperties;
  let minProp = this.state.rarity.minProperties;

  let rngCurrentPropAmount = Math.floor(Math.random() * (maxProp - minProp   1)   minProp);

  // the actual properties for an item based on the array of properties
  for (let i = 0; i < rngCurrentPropAmount; i  ) {
    let rngNum = Math.floor(Math.random() * (itemProperties.length))
    rngProperties.push(itemProperties[rngNum])
  }


  let proxyProperties = []

  // setting the values for each property based on the min and max of that property
  for (let j = 0; j < rngProperties.length; j  ) {
    let rngValue = this.getRandomNumber(rngProperties[j].min, rngProperties[j].max);
    rngProperties[j].value = rngValue;
  
    // creating a proxy to store unique values for each property,
    let obj = {
      id: rngProperties[j].id,
      name: rngProperties[j].name,
      min: rngProperties[j].min,
      max: rngProperties[j].max,
      value: rngProperties[j].value
    }
    proxyProperties.push(obj);
  }

  //setState() has an inbuilt functionality for a callback function, in which we can console.log the newly changed state
  this.setState({
    properties: proxyProperties
  }, () => {
    // console.log('propF', this.state)
  });
}

An expected output of the above code is the below picture. enter image description here

What I want to do is combine the 2 properties called (in this case) "Area Damage" so that only 1 property is listed but the value is 25 (again, in this case).

The itemProperties is an array of objects that have the following structure:

id: 1,
name: "intelligence",
min: 1,
max: 10,
value: 0

The rngCurrentPropAmount can be replaced with any integer for testing purposes. This is the amount of properties to be added.

CodePudding user response:

The logic is to first group the array by name then merge them using reduce & summing the value. Bit tricky but working. Hope this is what was needed. The initial array has 4 elements & the final one has two. value is summed up.

const arr = [
  {
    id: 1, name: "intelligence", min: 1, max: 10, value: 11
  },
  {
    id: 1, name: "intelligence", min: 1, max: 10, value: 4
  },
  {
    id: 2, name: "dexterity", min: 1, max: 10, value: 3
  },
  {
    id: 2, name: "dexterity", min: 1, max: 10, value: 8
  }
];

//group an array by property 
function groupBy(arr, property) {
  return arr.reduce(function(memo, x) {
    if (!memo[x[property]]) {
      memo[x[property]] = [];
    }
    memo[x[property]].push(x);
    return memo;
  }, {});
}

//group by name
const grouped = groupBy(arr, "name");
const keys = Object.keys(grouped);
var output = [];

//loop keys
keys.forEach(key => {
  //merge using reduce
  const out = grouped[key].reduce((acc, current) => {
    return {
      id: current.id,
      name: current.name,
      min: current.min,
      max: current.max,
      value: acc.value   current.value
    }
  });
  output.push(out);
});

console.log(output);

  • Related