-1

I want to make an array of objects grouped by the date property.

let data = [
        { Age: "(60-100)", Date: "28/05/20" },
        { Age: "(60-100)", Date: "28/05/20" },
        { Age: "(4-6)", Date: "28/05/20" },
        { Age: "(60-100)", Date: "29/05/20" },
        { Age: "(38-43)", Date: "29/05/20" },
        { Age: "(4-6)", Date: "29/05/20" },
        { Age: "(38-43)", Date: "30/05/20" },
        { Age: "(38-43)", Date: "30/05/20" }
    ];

I want the output like

 result = [
        { Date: "28/05/20", "(60-100)": 2, "(4-6)": 1 },
        { Date: "29/05/20", "(38-43)": 1, "(4-6)": 1, "(60-100)": 1 },
        { Date: "30/05/20", "(38-43)": 2 },
    ]
  • What about dates past `29/05/20`? Filter them out? Also your example output shows `{ Date: "28/05/20", "(38-43)": 2 }` but the input only has one `{ Age: "(38-43)", Date: "29/05/20" }` object. Also you have two entries for `28/05/20` in your output but just one entry for `29/05/20` and they don't appear to have any logic as to how they are sorted which is inconsistent. Did you make a mistake or leave some things out when explaining the output you want? – apena Jun 27 '20 at 21:47
  • Thanks for pointing that out, it has been updated :) – Khwaja Abdul Ahad Jun 28 '20 at 11:33
  • You are welcome. – apena Jun 28 '20 at 17:29

4 Answers4

2

Give this a try.

 let data = [
      { Age: "(60-100)", Date: "28/05/20" },
      { Age: "(60-100)", Date: "28/05/20" },
      { Age: "(4-6)", Date: "28/05/20" },
      { Age: "(60-100)", Date: "29/05/20" },
      { Age: "(38-43)", Date: "29/05/20" },
      { Age: "(4-6)", Date: "29/05/20" },
      { Age: "(38-43)", Date: "30/05/20" },
      { Age: "(38-43)", Date: "30/05/20" }
 ];
    
 let res = [];
 data.map((d, index) => {
      if (!res.some(val => val.Date === d.Date)) {
           d[`${d.Age}`] = 1
           res.push(d)
           delete(d.Age)
      } else {
           let index = res.findIndex(val => val.Date == d.Date);
           let _d = res[index];
           if (_d.hasOwnProperty(`${d.Age}`)) {
                _d[`${d.Age}`] = parseInt(_d[`${d.Age}`] + 1)
           } else {
                _d[`${d.Age}`] = 1
           }
           res[index] = _d;
      }
 })
 
 console.log(res)
Adam Harte
  • 9,820
  • 7
  • 48
  • 82
parse shyam
  • 341
  • 2
  • 9
1

Try this:

function groupByDate(data){
    let groupedData = [];
    data.forEach(element => {
        //Search for the object containing the specified date
        let objIndex = groupedData.findIndex(object => {return object.Date == element.Date;})
        //If date is not created, create it
        if (objIndex == -1){
            groupedData.unshift({Date: element.Date})
            objIndex = 0;
        }
        //If age is not created, create it. Else add 1 to specified age.
        if(typeof groupedData[objIndex][element.Age] == 'undefined'){
            groupedData[objIndex][element.Age] = 1;
        } else {
            groupedData[objIndex][element.Age]++;
        }
    });
    return groupedData;
}

If you also want to sort by date, you could check out this post. Hope it helped you!

Dante Culaciati
  • 101
  • 1
  • 9
0

try this:

var result={};
for(var item of data) {
  if(result[item.Date]==undefined) result[item.Date]={};
  if(result[item.Date][item.Age]==undefined) result[item.Date][item.Age]=0;
  result[item.Date][item.Age]++;
}

This gives you an object (not an array) with keys of Date and values as object with keys of Age and values as count.
If you still need an array, you can iterate over the result and construct an array.

result=={
  "28/05/20": {
    "(60-100)": 2,
    "(4-6)": 1
  },
  "29/05/20": {
    "(60-100)": 1,
    "(38-43)": 1,
    "(4-6)": 1
  },
  "30/05/20": {
    "(38-43)": 2
  }
}

If you want the array, you can create resultArr=[], iterate over keys of result, tempObj, add key "Date" and value of iterated key, then iterate over keys of iterated key, add each "Age" with it's count, then push tempObj into resultArr...

iAmOren
  • 2,609
  • 2
  • 9
  • 23
0

Condensed version based on @Dante Culaciati approach with optional sort parameter.

const condenseAge = (arr, isSort = true) => {
    let r = [];
    arr.map((val) => {
        let i = r.findIndex(obj => obj.Date == val.Date);
        (i < 0) && r.unshift({Date: val.Date}) && (i = 0);
        (!r[i][val.Age]) ? r[i][val.Age] = 1 : r[i][val.Age]++;
    });
    return !isSort?r:r.sort((a,b)=>(ac=a['Date'].split('/'), bc=b['Date'].split('/'), new Date(ac[2],ac[1],ac[0]) - new Date(bc[2],bc[1],bc[0])));
}
console.log(condenseAge([
    { Age: "(4-6)", Date: "02/06/20"},
    { Age: "(60-100)", Date: "28/05/20" },
    { Age: "(60-100)", Date: "28/05/20" },
    { Age: "(4-6)", Date: "28/05/20" },
    { Age: "(60-100)", Date: "29/05/20" },
    { Age: "(38-43)", Date: "29/05/20" },
    { Age: "(4-6)", Date: "29/05/20" },
    { Age: "(38-43)", Date: "30/05/20" },
    { Age: "(38-43)", Date: "30/05/20" }
]));
apena
  • 1,486
  • 7
  • 18
  • Kudos to you this is a good approach, but I just used Array.reverse(). – Khwaja Abdul Ahad Jun 29 '20 at 13:59
  • Thats fine but it will fail if the data input is not in reverse chronological order every time. Assuming data order from API's is not the best practice. – apena Jun 29 '20 at 15:20
  • 1
    Your solution is still not perfect, if you'll add another months data like '02/06/20' then it will show '02/06/20' before '28/05/20'. – Khwaja Abdul Ahad Jun 30 '20 at 09:15
  • changed 'ac[0],ac[1],ac[2]' to 'ac[2],ac[1],ac[0]'. – Khwaja Abdul Ahad Jun 30 '20 at 09:27
  • Good catch. I didn't test the function much, turns out I was passing the arguments out of order to the `Date` method so only the day was being sorted. I changed `bc[2],bc[1],bc[0]' to 'bc[2],bc[1],bc[0]` as well. – apena Jun 30 '20 at 17:10