ketan
ketan

Reputation: 19341

Total array of object based on another array value

I am trying to create new array of object with total data by year(or any selected key) but, it doesn't work as expected.

const dataArray = [
  {
    "abc": 10,
    "xyz": 20,
    "year": "2021"
  },
  {
    "abc": 20,
    "xyz": 20,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 30,
    "xyz": 10,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 10,
    "xyz": 10,
    "year": "2022"
  }
]
const keys = ["year", "abc", "xyz"];
const cols = ["year"]

//expected
//[{ "abc": total of abc for 2021, "xyz": total of xyz for 2021, "year" "2021"}, { "abc": total of abc for 2022, "xyz": total of xyz for 2022, "year" "2022"}]

const newObject = {};
cols.forEach(col => {
 dataArray.forEach(arr => {
  keys.forEach(key => {
    if(col != key) {
      newObject[key] += col[key]
    }
  })
 })
})

console.log(newObject);

I tried above but doesn't work as expected.

My expectation is:

[
  {
    "abc": "total of abc for 2021",
    "xyz": "total of xyz for 2021",
    "year": "2021"
  },
  {
    "abc": "total of abc for 2022",
    "xyz": "total of xyz for 2022",
    "year": "2022"
  }
]

Upvotes: 0

Views: 64

Answers (3)

Xupitan
Xupitan

Reputation: 1681

const dataArray = [
  {
    "abc": 10,
    "xyz": 20,
    "year": "2021"
  },
  {
    "abc": 20,
    "xyz": 20,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 30,
    "xyz": 10,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 10,
    "xyz": 10,
    "year": "2022"
  }
]

const result = dataArray.reduce((res, ele) => {
  let exist = res.find(e => e.year === ele.year)
  if(exist) {
    exist.abc += ele.abc
    exist.xyz += ele.xyz
  } else {
    res = [...res, {...ele}]
  }
  return res
}, [])

// other way
const result1 = Object.values(
  dataArray.reduce((res, {year, ...rest}) => {
    let ele = res[year] ??= {year}
    Object.entries(rest).forEach(([k, v]) => ele[k] = (ele[k] ?? 0)  + v)
    return res
  }, {})
)
console.log(result, result1)

Upvotes: 1

HiddenOne1254
HiddenOne1254

Reputation: 146

if you want some different approach

  const dataArray = [
  {
    "abc": 10,
    "xyz": 20,
    "year": "2021"
  },
  {
    "abc": 20,
    "xyz": 20,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 30,
    "xyz": 10,
    "year": "2022"
  },
  {
    "abc": 20,
    "xyz": 10,
    "year": "2021"
  },
  {
    "abc": 10,
    "xyz": 10,
    "year": "2022"
  }
]
let mainObj = {}
dataArray.forEach((el)=>{
    if(!mainObj.hasOwnProperty(el.year)){
        mainObj[el.year] = {}
        mainObj[el.year].abc = el.abc
        mainObj[el.year].xyz = el.xyz
        mainObj[el.year].year = el.year
    }
    else{
        mainObj[el.year].abc = mainObj[el.year].abc + el.abc
        mainObj[el.year].xyz = mainObj[el.year].xyz + el.xyz
        
    }
})
let values = Object.values(mainObj)
console.log(values)

Upvotes: 0

Nick
Nick

Reputation: 147266

You can aggregate dataArray using reduce, building an object whose keys are the year values and values are the accumulated abc and xyz values. You can then convert that into your desired array format using Object.values:

const dataArray = [{
    "abc": 10, "xyz": 20, "year": "2021"
  },
  {
    "abc": 20, "xyz": 20, "year": "2022"
  },
  {
    "abc": 20, "xyz": 10, "year": "2021"
  },
  {
    "abc": 30, "xyz": 10, "year": "2022"
  },
  {
    "abc": 20, "xyz": 10, "year": "2021"
  },
  {
    "abc": 10, "xyz": 10, "year": "2022"
  }
]

const keys = ["year", "abc", "xyz"];
const cols = ["year"]

newObject = Object.values(
  dataArray.reduce((acc, obj) => {
    colkey = cols.map(k => obj[k]).join('##')
    if (acc.hasOwnProperty(colkey)) {
      keys.filter(k => !cols.includes(k)).forEach(k => acc[colkey][k] += obj[k])
    } else {
      acc[colkey] = obj
    }
    return acc
  }, {})
);

console.log(newObject);
.as-console-wrapper { max-height: 100% !important }

Upvotes: 4

Related Questions