skip to Main Content

I have an array with objects like this:

[
  {date: 2023-05-06, group: 'groupA'},
  {date: 2023-05-05, group: 'group1'},
  {date: 2023-05-07, group: 'groupA'},
  {date: 2023-05-08, group: 'group1'},
]

I would like to get an array where the newest element is the first and the elements are grouped by the group property which is a string.

Expected result:

[
  {date: 2023-05-08, group: 'group1'},  // newest in array
  {date: 2023-05-05, group: 'group1'},  // second newest in same group
  {date: 2023-05-07, group: 'groupA'},  // second newest in array
  {date: 2023-05-06, group: 'groupA'},  // second newest in same group
]

3

Answers


  1. We’d create a groupBy function to allow us to group any array by an arbitrary key.

    We’ll sort our input by date first then group.

    Finally we’ll get all values and flatten using Object.values() and Array.flat():

    const input = [
      {date: '2023-05-06', group: 'groupA'},
      {date: '2023-05-05', group: 'group1'},
      {date: '2023-05-07', group: 'groupA'},
      {date: '2023-05-08', group: 'group1'},
    ]
    
    function groupBy(input, key) {
        return input.reduce((acc, el) => { 
            acc[el[key]] = acc[el[key]] || [];
            acc[el[key]].push(el);
            return acc;
        }, {});
    }
    
    // Group by 'group', but sort first...
    const inputSortedByDate = input.sort((a,b) => Date.parse(b.date) - Date.parse(a.date));
    const grouped = groupBy(inputSortedByDate, 'group');
    
    // Get flattened result...
    const result = Object.values(grouped).flat();
    console.log('Result:', result)
    Login or Signup to reply.
  2. You need to find max date per group before you can decide which group sorts first. Then for items within same group you sort them by date:

    let array = [
      { date: "2023-05-06", group: "groupA" },
      { date: "2023-05-05", group: "group1" },
      { date: "2023-05-07", group: "groupA" },
      { date: "2023-05-08", group: "group1" },
    ];
    let maxDatePerGroup = {};
    array.forEach(item => {
      if (maxDatePerGroup[item.group] === undefined || maxDatePerGroup[item.group] < item.date) {
        maxDatePerGroup[item.group] = item.date;
      }
    })
    array.sort((a, b) => {
      let ai = maxDatePerGroup[a.group];
      let bi = maxDatePerGroup[b.group];
      return new Date(bi) - new Date(ai) || new Date(b.date) - new Date(a.date);
    });
    console.log(array);
    Login or Signup to reply.
  3. Looking at the result exemple you provided, I think this would work for you.

    You can solve this by grouping by group and sorting each group individually. Finally, you can merge the sorted groups in a single array (this should keep the array sorted because you are iterating it by order)

    const input = [
        { date: '2023-05-06', group: 'groupA' },
        { date: '2023-05-05', group: 'group1' },
        { date: '2023-05-07', group: 'groupA' },
        { date: '2023-05-08', group: 'group1' },
    ];
    
    // stage 1: group
    const grouped = {};
    input.forEach((el) => {
        if (grouped[el.group] && grouped[el.group].length > 0) {
            grouped[el.group].push(el);
        } else {
            grouped[el.group] = [el];
        }
    });
    
    // stage 2: sort by date
    const sortedGroupes = Object.values(grouped).map((el) => {
        return el.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
    });
    
    // stage 3: merge sorted groupes
    const output = [];
    sortedGroupes.forEach((grp) => output.push(...grp));
    console.log(output);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search