简体   繁体   中英

Create new object based on filtered data

i need some help. I need to calculate the amount of user actions in each month of current year. I have an array of dates:

let years = ['2017', '2018', '2019']
let datesArray = [
    {date: "2019-06-05", userActionsAmount: 88},
    {date: "2019-06-04", userActionsAmount: 314}
]

and i have the count object

let counts = {}

then i iterate thru this like that:

years.forEach(year => {
          counts[year] = datesArray.filter(singleDay => singleDay.date.slice(0, -6) === year).reduce((acc, obj) => {
            return acc + obj.userActionsAmount
          }, 0)
        })

with this code result of counts is: {2017: 0, 2018: 0, 2019: 402} wich is ok, but i need to break the date in to months, so i need something like this:

{ 2017: []},
{ 2018: []}
{ 2019: [
  { '01': 0 },
  { '02': 0 },
  { '03': 0 },
  { '04': 0 },
  { '05': 0 },
  { '06': 402 },
  { '07': 0 },
  { '08': 0 },
  { '09': 0 },
  { '10': 0 },
  { '11': 0 },
  { '12': 0 }
]}

you can do it like this:

 let datesArray = [ {date: "2019-06-05", userActionsAmount: 88}, {date: "2019-06-04", userActionsAmount: 314} ] let result={}; datesArray.forEach(dateItem=>{ let date=dateItem.date.split("-"); let year=date[0]; let month=date[1]; if(!result[year]) result[year]={}; if(!result[year][month]) result[year][month]=0; result[year][month]+=dateItem.userActionsAmount; })

You could create properties when needed. Here are two solutions : one with array methods and second more explicit.

Initialization :

const monthsKeys = ["01", "02", "03","04", "05", "06", "07", "08", "09", "10", "11", "12"];
const years = ['2017', '2018', '2019'];
const datesArray = [
    {date: "2019-06-05", userActionsAmount: 88},
    {date: "2019-06-04", userActionsAmount: 314}
];
const counts = {};

Solution 1 :

years.forEach( y => { counts[y] = []; });
datesArray.forEach(dateCount => { 
    const [year, month, day] = dateCount.date.split("-");
    if (counts[year].length === 0) monthsKeys.forEach(m => {counts[year].push({[m] : 0});});
    counts[year][Number(month) - 1][month] += dateCount.userActionsAmount;
});
console.log(counts);

Solution 2 :

// fill counts with years
for (const y of years) {
    counts[y] = [];
}

// fill counts with months and count
for (const e of datesArray) {
    const splittedDate = e.date.split("-");
    const year = splittedDate[0];
    const month = splittedDate[1];

    // create year if needed, not necessary if years array is sure
    if ( ! year in counts) {
        counts[year] = [];
    }

    // create monthes if needed
    if (counts[year].length === 0) {
        for (const m of monthsKeys) {
             counts[year].push({[m]: 0});
        }  
    }

    // add value
    counts[year][Number(month) - 1][month] += e.userActionsAmount;
}
console.log(counts)

Why an array of objects for year values (months counts) and not simply an object?

That's basically a very simple grouping

 const datesArray = [ {date: "2019-06-05", userActionsAmount: 88}, {date: "2019-06-04", userActionsAmount: 314} ]; const groupedByMonth = datesArray.reduce((a, b) => a.set(b.date.substring(0,7), ~~a.get(b.date.substring(0,7)) + b.userActionsAmount), new Map); console.log([...groupedByMonth]);

To get it to your format, you could do something like

const yourFormat = years.map(e => ({
  [e]: Array.from(groupedByMonth).filter(([k, v]) => k.substring(0,4) === e).map(([k, v]) => ({[k.substring(5,7)]: v}))
})); 

then

This solution has some varation from the OP's expected output, but I believe that it should fit OP's requirements. If not, it's about a step to get the output as desired...

 const years = [2017, 2018, 2019] const dates = [{ date: "2019-06-05", userActionAmount: 88 }, { date: "2019-06-04", userActionAmount: 314 } ] const transform = (years, dates) => dates.reduce( (output, { date, userActionAmount, parsedDate = new Date(date), year = parsedDate.getFullYear(), month = parsedDate.getMonth() + 1, yearData = output[year] }) => (yearData[month] += userActionAmount) && output, Object.fromEntries(years.map(year => [year, Object.fromEntries(Array.from({ length: 12 }, (_, x) => [x + 1, 0]))]))) const output = transform(years, dates) console.log(output) // This output lets you get total amount // of some given month in the following way: const monthAmount = output[2019][6] console.log (monthAmount)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM