Home > Blockchain >  How to sort any array of a nested data structure by an item's either date related property valu
How to sort any array of a nested data structure by an item's either date related property valu

Time:12-21

My purpose is to get from this:

const grouped = [
  {
    "2022/11": [
      {
        "2022/11/30": [
          {
            "breaking-change": [
              {
                date: "2022-11-30T07:33:07.992955008Z",
                reponame: "test-repo",
                status: "breaking-change",
              },
            ],
          },
        ],
      },
      {
        "2022/11/29": [
          {
            compatible: [
              {
                date: "2022-11-29T14:58:44 01:00",
                reponame: "test-repo",
                status: "compatible",
              },
            ],
          },
        ],
      },
    ],
  },
  {
    "2022/10": [
      {
        "2022/10/17": [
          {
            compatible: [
              {
                date: "2022-10-17T14:58:44 01:00",
                reponame: "test-repo",
                status: "compatible",
              },
            ],
          },
        ],
      },
    ],
  },
];

This:

[
  {
    "2022/10": [
      {
        "2022/10/17": [
          {
            compatible: [
              {
                date: "2022-10-17T14:58:44 01:00",
                reponame: "test-repo",
                status: "compatible",
              },
            ],
          },
        ],
      },
    ],
  },
  {
    "2022/11": [
      {
        "2022/11/29": [
          {
            compatible: [
              {
                date: "2022-12-17T14:58:44 01:00",
                reponame: "test-repo",
                status: "compatible",
              },
            ],
          },
        ],
      },
      {
        "2022/11/30": [
          {
            "breaking-change": [
              {
                date: "2022-11-30T07:33:07.992955008Z",
                reponame: "test-repo",
                status: "breaking-change",
              },
            ],
          },
        ],
      },
    ],
  },
];

So:

  1. "month-objects" ( the example would be the one in the parent array with 2022/11 as a key ) needs to be sorted by key(date/month) in an ascending way;

  2. and also "days-objects" (the example would be the one in the first-level-children array with 2022/11/30 as a key ) needs to be sorted by key(date/month) in an ascending way;

That's what I tried:

const sortedGrouped = grouped.sort(function (a, b) {
  return (
    new Date(Object.keys(a)[0]).getTime() -
    new Date(Object.keys(b)[0]).getTime()
  );
}); 

That way I can only sort parents.

Tried to sort first-level children, but getting an Invalid left-hand side in assignment expression issue:

grouped.forEach((obj) => {
  Object.values(obj) = Object.values(obj).sort(function (a, b) {
    return (
      new Date(Object.keys(a)[0]).getTime() -
      new Date(Object.keys(b)[0]).getTime()
    );
  });
});

This one doesn't work for me either:

const sortByDate = arr => {
   const sorter = (a, b) => {
      return new Date(Object.keys(a)[0]).getTime() - new Date(Object.keys(b)[0]).getTime();
   };
   arr.forEach((i)=>Object.values(i).sort(sorter))
   return arr;
};

CodePudding user response:

The most generic solution has to based on a recursive approach.

Thus one does

  • either
    • try to sort an array by retrieving a Date related value from each of its items,
    • and keep the recursion going for each item of the just sorted array,
  • or
    • keep the recursion going for each value of an object type item.

Which directly leads to two other tasks

  • a function which from each passed object tries to parse a valid Date instance from

  • and a helper function which checks whether a passed value is a valid date.

The first mentioned of the latter two functions does so by either assuming an existing date property of the passed value or by going with the first validly parsed date from one of the passed value's keys.

function isValidDate(date) {
  const time = date?.getTime?.() ?? Number.NaN;
  return (
    'number' === typeof time
    && !Number.isNaN(time)
  );
}
function parseDateFromItem({ date: dateTime = null, ...itemData }) {
  let date;

  // parse into a `Date` instance ...
  if (dateTime !== null) {

    // ... either directly from an available `date` key ...
    date = new Date(dateTime);
  } else {
    // ... or from the first validly parsable property name.
    Object
      .keys(itemData)
      .some(key => {
        date = new Date(key);
        return isValidDate(date);
      });
  }
  return isValidDate(date) && date || null;
}

function recursivelySortItemsAscendingByParsableDate(data) {
  if (Array.isArray(data)) {

    data
      .sort((a, b) =>
        (parseDateFromItem(a) ?? 0) - (parseDateFromItem(b) ?? 0)
      );
    data
      .forEach(recursivelySortItemsAscendingByParsableDate);

  } else if (data && 'object' === typeof data) {

    Object
      .values(data)
      .forEach(recursivelySortItemsAscendingByParsableDate);
  }
}


const sampleData = [{
  "2022/11": [{
    "2022/11/30": [{
      "breaking-change": [{
        date: "2022-11-30T07:33:07.992955008Z",
        reponame: "test-repo",
        status: "breaking-change",
      }],
    }],
  }, {
    "2022/11/29": [{
      compatible: [{
        date: "2022-11-29T14:58:44 01:00",
        reponame: "test-repo",
        status: "compatible",
      }],
    }],
  }],
}, {
  "2022/10": [{
    "2022/10/17": [{
      compatible: [{
        date: "2022-10-17T14:58:44 01:00",
        reponame: "test-repo",
        status: "compatible",
      }],
    }],
  }],
}];

recursivelySortItemsAscendingByParsableDate(sampleData);
console.log({ sampleData });


const moreSampleData = [{
  "2022/12": [{
    "2022/12/17": [{
      compatible: [{
        date: "2022-12-17T14:58:44 01:00",
        reponame: "test-repo",
        status: "compatible"
      }]
    }]
  }]
}, {
  "2021/11": [{
    "2021/11/30": [{
      compatible: [{
        date: "2021-11-30T07:33:07.992956372Z",
        reponame: "test-repo",
        status: "compatible"
      }]
    }]
  }]
}, {
  "2022/11": [{
    "2022/11/30": [{
      compatible: [{
        date: "2022-11-30T07:33:07.992956372Z",
        reponame: "test-repo",
        status: "compatible"
      }, {
        date: "2022-11-25T07:33:07.992955008Z",
        reponame: "test-repo",
        status: "compatible"
      }]
    }, {
      "breaking-change": [{
        date: "2022-11-30T07:33:07.992955008Z",
        reponame: "test-repo",
        status: "breaking-change"
      }]
    }, {
      "need-an-update": [{
        date: "2022-11-30T07:33:07.992955008Z",
        reponame: "test-repo",
        status: "need-an-update"
      }]
    }]
  }, {
    "2022/11/29": [{
      compatible: [{
        date: "2022-12-17T14:58:44 01:00",
        reponame: "test-repo",
        status: "compatible"
      }]
    }]
  }]
}];

recursivelySortItemsAscendingByParsableDate(moreSampleData);
console.log({ moreSampleData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related