根据日期对对象数组进行排序

时间:2020-04-16 15:17:54

标签: javascript arrays sorting date

[
0: {date: "02-04-2020", count: 1}
1: {date: "16-04-2020", count: 2}
2: {date: "10-04-2020", count: 1}
3: {date: "15-04-2020", count: 4}
4: {date: "04-04-2020", count: 4}
]

从上面的对象数组中,我需要根据日期对它们进行排序,并按以下方式获取输出

    [
    0: {date: "02-04-2020", count: 1}
    1: {date: "04-04-2020", count: 4}
    2: {date: "10-04-2020", count: 1}
    3: {date: "15-04-2020", count: 4}
    4: {date: "16-04-2020", count: 2}
    ]

我尝试使用以下方法

const sorted_array = data
          .slice()
          .sort(
            (a, b) => new Date(a.date).valueOf() - new Date(b.date).valueOf()
          );

我在排序前使用了.slice,因为出现错误Cannot assign to read only property '0' of object '[object Array],所以我引用了Error while sorting array of objects Cannot assign to read only property '2' of object '[object Array]'并添加了slice。

但是排序没有正确完成,我需要一些帮助来解决。谢谢。

3 个答案:

答案 0 :(得分:2)

您可能会遇到new Date(...)不能处理这种格式的字符串的问题,因为它不是标准格式。 new Date("02-04-2020")将其解释为2020年2月4日,并且new Date("16-04-2020")产生错误。此处似乎使用美国日期格式,而我们日后使用前一个月。

如果您的日期格式为yyyy-mm-dd,则new Date(...)可以正常使用,因此,如果您能够进行更改,那将是最顺畅的路线。如果您无法更改格式,则需要考虑更改排序方式:

const sorted_array = data
  .map(addSortableColumn)
  .sort(bySortColumn)
  .map(removeSortableColumn);

function addSortableColumn(item) {
  const [day, month, year] = item.date.split('-');
  return { ...item, _sortBy: year + month + day };
}

function bySortColumn(a, b) {
  return a._sortBy.localeCompare(b._sortBy);
}

function removeSortableColumn(item) {
  const { _sortBy, ...otherProps } = item;
  return otherProps;
}

(如果您不想删除排序列,则可以跳过最后一步)

更新

如果您需要保留对象原型,则正确地指出,传播语法会破坏这一点。我实际上更喜欢的另一种方法是将排序列存储在单独的映射中。之所以要存储它,是为了避免需要多次计算排序键。

const sortKeys = new Map();

const sorted_array = data.slice().sort(byDDMMYYYY);

function byDDMMYYYY(a, b) {
  return getSortKey(a).localeCompare(getSortKey(b));
}

function getSortKey(item) {
  let key = sortKeys.get(item);
  if (!key) {
    const [day, month, year] = item.date.split('-');
    key = year + month + day;
    sortKeys.set(item, key);
  }
  return key;
}

答案 1 :(得分:2)

有关您的错误的解释,请参见@Jacob的答案。这是使用正则表达式将日期更改为正确格式的替代解决方案:

const pattern = /(\d{2})-(\d{2})-(\d{4})/;
const repl = "$3-$2-$1";
const sorted_array = data
      .slice()
      .sort(
          (a, b) => new Date(a.date.replace(pattern, repl)) - 
                    new Date(b.date.replace(pattern, repl))
      );

还请注意,您不需要比较valueOf()中的DateDate的算术已经很重载,可以对对象进行本机比较。

编辑:根据specification,将repl更改为与ISO 8601兼容的YYYY-MM-DD格式。

答案 2 :(得分:1)

您的日期格式不正确。 DD-MM-YYYY是无效的日期格式。

new Date("15-04-2020")

将返回无效日期

您需要将日期转换为ISO日期格式YYYY-MM-DD according to the specification

const data = [ 
  {_id: "02-04-2020", count: 1},
  {_id: "16-04-2020", count: 2},
  {_id: "10-04-2020", count: 1},
  {_id: "15-04-2020", count: 4},
  {_id: "04-04-2020", count: 4},
];

console.log("Original Data: ", data);

// Something like that.
const dataSorted = data.slice().sort((a, b) => {
  const [dayA, monthA, yearA] = a._id.split("-");
  const [dayB, monthB, yearB] = b._id.split("-");
  return new Date(`${yearA}-${monthA}-${dayA}`) 
    - new Date(`${yearB}-${monthB}-${dayB}`)
});

console.log("Data sorted by date: ", dataSorted);