Home > Blockchain >  array of object with a range date
array of object with a range date

Time:07-11

i have an array of object. every object has a date. I want to create a new array of object, grouping by weeks. here is some code example:

const data = [
  {
    "id": 1,
    "status": 1,
    "createdAt": "2022-05-01T08:28:36.284Z"
  },
  {
    "id": 2,
    "status": 2,
    "createdAt": "2022-05-02T07:17:11.724Z"
  },
  {
    "id": 3,
    "status": 3,
    "createdAt": "2022-05-10T07:03:44.465Z"
  },
  {
    "id": 4,
    "status": 3,
    "createdAt": "2022-05-11T16:17:48.863Z"
  }
]

The result I want Is an array that divides object by weeks like:

const newData = [
  {
    "week": 1,
    "status": 1,
    "status": 2
  },
  {
    "week": 2,
    "status": 3,
    "status": 3
  }]

is it possible? can I have same property 2 times in the same object? thank you

CodePudding user response:

You should import and use moment.js to find the week number, for charting purposes I would suggest something like this:

const data = [
  {
    "id": 1,
    "status": 1,
    "createdAt": "2022-05-01T08:28:36.284Z"
  },
  {
    "id": 2,
    "status": 2,
    "createdAt": "2022-05-02T07:17:11.724Z"
  },
  {
    "id": 3,
    "status": 3,
    "createdAt": "2022-05-10T07:03:44.465Z"
  },
  {
    "id": 4,
    "status": 3,
    "createdAt": "2022-05-11T16:17:48.863Z"
  }
]
console.log(data.map(a => {
        return {
        status : a.status,
        week: moment(a.createdAt).week()
    }
    }
))
<script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>

This will return and array like this:

[{
  status: 1,
  week: 19
}, {
  status: 2,
  week: 19
}, {
  status: 3,
  week: 20
}, {
  status: 3,
  week: 20
}]

CodePudding user response:

In ECMAScript, an object can't have multiple properties with the same name. However, an option is to have an array of objects like:

[{week: weekNo, statuses: [status0, status1, status2, …]}]

Week numbers repeat each year, so you should include the year, perhaps using an ISO 8601 format like 2022W03 that is easy to parse and sorts lexically. That will also deal with dates going over a new year.

Array.prototype.reduce with a function to calculate the week number can do the job:

// Return ISO week number: week starts on Monday,
// first week of year is the one containing 4 Jan or 
// first Thursday of the year
function getWeekNumber(d) {
    let z = n => (n<10? '0' : '')   n; 
    d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
    d.setUTCDate(d.getUTCDate()   4 - (d.getUTCDay()||7));
    var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
    var weekNo = Math.ceil(( ( (d - yearStart) / 86400000)   1)/7);
    return `${d.getUTCFullYear()}W${z(weekNo)}`;
}

function groupByWeek(data) {
  // Pointer to location of week in array
  let index = {};
  let newData = data.reduce((acc, obj) => {
    let weekNo = getWeekNumber(new Date(obj.createdAt));
    if (!index[weekNo]) {
      index[weekNo] = acc.length;
      acc.push({week: weekNo, statuses: []});
    }
    acc[index[weekNo]].statuses.push(obj.status);
    return acc;
  }, []);
  // Sort by week number
  newData.sort((a, b) => a.week.localeCompare(b.week));
  return newData;
}

let data = [
  {"id": 1, "status": 1, "createdAt": "2022-05-01T08:28:36.284Z"},
  {"id": 2, "status": 2, "createdAt": "2022-05-02T07:17:11.724Z"},
  {"id": 3, "status": 3, "createdAt": "2022-05-10T07:03:44.465Z"},
  {"id": 4, "status": 3, "createdAt": "2022-05-11T16:17:48.863Z"},
  {"id": 5, "status": 1, "createdAt": "2023-01-05T08:28:36.284Z"},
];

console.log(groupByWeek(data))

CodePudding user response:

As we can't have multiple property properties with the same name in an object you should store status in an array.

let getWeekNbr = date => {
    var oneJan = new Date(date.getFullYear(),0,1);
    var numberOfDays = Math.floor((date - oneJan) / (24 * 60 * 60 * 1000));
    return Math.ceil(( date.getDay()   1   numberOfDays) / 7);
}

let formateDate = date => new Date(Date.parse(date));

let groupBy = (arr, key) => {
    return arr.reduce((rv, x) => {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
    }, {});
};

let formatedData = data.map(d => ({...d, week: getWeekNbr(formateDate(d.createdAt))}));                          // calcule week nbr
let groupedData = groupBy(formatedData, 'week');                                                                 // group data by week propertie's value
let result = Object.values(groupedData).map(arr => ({week: arr.at(0).week, status: arr.map(d => d.status)}));    // formating result

console.log(result);

// Output
// [
//     { "week": 18, "status": [1, 2] },
//     { "week": 19, "status": [3] },
//     { "week": 20, "status": [3] }
// ]
  • Related