给定条件,将一系列项目划分为几个阵列



这个问题非常简单:我有一系列的项目,它们都有一个日期。根据日期,我想将此数组分为几个数组。

就我而言,我想将数组分为3个数组:一个包含最后24小时的结果,另一个48h,然后是本周的最后一个。

这是该案例的最小再现,最终解决方案。

const now = Date.now();
const day = 1000 * 3600 * 24;
const todayTime = now - day;
const yesterdayTime = now - day * 2;
const weekTime = now - day * 7;
const arr = [
  { id: 1, date: todayTime + 100 },
  { id: 2, date: yesterdayTime + 100 },
  { id: 3, date: weekTime + 100 },
];
const today = arr.filter(item => item.date - todayTime > 0);
const yesterday = arr.filter(item => item.date - yesterdayTime > 0 && item.date - todayTime < 0);
const week = arr.filter(item => item.date - weekTime > 0 && item.date - yesterdayTime < 0);
console.log(today, yesterday, week);

有没有办法使它更简洁?我说的是代码长度:我想将其简化为最大值,尤其是3个阵列的定义。我尝试了减少,但语法很丑。

有什么想法吗?

它不是短的,但是我会选择一个更通用的功能,该功能将数据基于给定属性(在您的情况下为"日期")和某些边界值分组到块中(您有3),按升序提供。然后该功能将返回一个值,因为3个边界将无限范围分为4个范围,等等。

所以这就是该功能的样子:

function groupInRanges(data, prop, boundaries) {
    // NB: boundaries must be sorted ascending.
    return data.reduce((acc, item) => {
        let index = boundaries.findIndex(boundary => item[prop] < boundary);
        if (index < 0) index = boundaries.length;
        acc[index].push(item);
        return acc;
    }, [[], ...boundaries.map(() => [])]);
}
// Demo
const now = Date.now();
const day = 1000 * 3600 * 24;
const arr = [
  { id: 1, date: now - day + 100 },
  { id: 2, date: now - 2*day + 100 },
  { id: 3, date: now - 5*day },
];
// We are not interested in the first value (data older than 1 week):
const [, week, yesterday, today] = groupInRanges(arr, "date", [now-day*7, now-day*2, now-day]);
console.log(today, yesterday, week);

请注意,如果您的数据可能具有 Future 日期,则需要将一个额外的边界设置为now

更具体的解决方案

这假定没有比一周或将来更早的数据。使用三元运算符来确定应推动数据项的数组:

const now = Date.now();
const day = 1000 * 3600 * 24;
const todayTime = now - day;
const yesterdayTime = now - day * 2;
const weekTime = now - day * 7;
const arr = [
  { id: 1, date: todayTime + 100 },
  { id: 2, date: yesterdayTime + 100 },
  { id: 3, date: weekTime + 100 },
];
const [today, yesterday, week] = arr.reduce((acc, item) => {
    acc[item.date > todayTime ? 0 : item.date > yesterdayTime ? 1 : 2].push(item);
    return acc;
}, [[], [], []]);
console.log(today, yesterday, week);

使用逗号运算符和表达式箭头功能语法短,但较不可读性:

const [today, yesterday, week] = arr.reduce((acc, item) =>
    (acc[item.date > todayTime ? 0 : item.date > yesterdayTime ? 1 : 2].push(item), acc)
, [[], [], []]);

您可以将功能移动到数组中,并获取以后推出项目的索引。

const
    update = (array, index, value) => {
        if (index !== -1) (array[index] = array[index] || []).push(value);
        return array;
    },
    now = Date.now(),
    day = 1000 * 3600 * 24,
    todayTime = now - day,
    yesterdayTime = now - day * 2,
    weekTime = now - day * 7,
    arr = [{ id: 1, date: todayTime + 100 }, { id: 2, date: yesterdayTime + 100 }, { id: 3, date: weekTime + 100 }],
    fns = [
       date => date - todayTime > 0,
       date => date - yesterdayTime > 0 && date - todayTime < 0,
       date => date - weekTime > 0 && date - yesterdayTime < 0,
    ],
    result = arr.reduce(
        (r, item) => update(r, fns.findIndex(f => f(item.date)), item),
        fns.map(_ => [])
    );
console.log(result);

您想使以下部分更简洁吗?

const today = arr.filter(item => item.date - todayTime > 0);
const yesterday = arr.filter(item => item.date - yesterdayTime > 0 && item.date - todayTime < 0);
const week = arr.filter(item => item.date - weekTime > 0 && item.date - yesterdayTime < 0);

这是我尝试的:

const [today, yesterday, week] = arr.reduce((result, item) => (index = item.date - todayTime > 0 ? 0 : item.date - yesterdayTime > 0 && item.date - todayTime < 0 ? 1 : 2, result[index].push(item), result), [[], [], []])

最终代码是:

const now = Date.now();
const day = 1000 * 3600 * 24;
const todayTime = now - day;
const yesterdayTime = now - day * 2;
const weekTime = now - day * 7;
const arr = [
  { id: 1, date: todayTime + 100 },
  { id: 2, date: yesterdayTime + 100 },
  { id: 3, date: weekTime + 100 },
];
// revised
const [today, yesterday, week] = arr.reduce((result, item) => (index = item.date - todayTime > 0 ? 0 : item.date - yesterdayTime > 0 && item.date - todayTime < 0 ? 1 : 2, result[index].push(item), result), [[], [], []])
console.log(today, yesterday, week)

这是使用map而不是reduce的另一个选项,就像其他大多数答案一样。

这只是通过比较日期来起作用,如果符合某个标准,则从数组中删除item。在下面的示例中,我复制了数组,使旧的arr完整。但是,如果您不关心arr突变,或者您想查看哪些项目不符合任何条件(因为它们被遗留在后面)。

我需要reverseEach函数的原因很明显。如果我开始从目前在元素上迭代的数组中删除项目,则开始转移。从背到正面迭代时,这并不重要,因为我已经处理了这些项目。

在下面的示例中,订单很重要。当您将t1w(时间为1周)作为数组中的第一个元素时,arr的所有元素都将匹配该条件,并将存在于该组中。确保您提供标准增量(或根据上下文减少)。

// define some helpers
Array.prototype.deleteAt = function (index) { return this.splice(index, 1)[0]; };
Array.prototype.dup = function () { return this.slice(0); };
Array.prototype.reverseEach = function (callback, thisArg) {
  if (thisArg !== undefined) callback = callback.bind(thisArg);
  for (let index = this.length - 1; index >= 0; index -= 1) {
    callback(this[index], index, this);
  }
};
// initialisation
const now = Date.now();
const day = 1000 * 3600 * 24;
const t1d = now - day;
const t2d = now - day * 2;
const t1w = now - day * 7;
const arr = [
  { id: 1, date: t1d + 100 },
  { id: 2, date: t2d + 100 },
  { id: 3, date: t1w + 100 },
];
// actual answer
const groups = [t1d, t2d, t1w].map(function (limit) {
  const group = [];
  this.reverseEach((item, index) => {
    if (item.date > limit) group.unshift(this.deleteAt(index));
  });
  return group;
}, arr.dup());
console.log(groups);

最新更新