给定条件,将项目数组拆分为几个数组

时间:2019-03-01 12:16:51

标签: javascript

问题很简单:我有一系列项目,每个项目都有一个日期。根据日期,我想将此数组拆分为几个数组。

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

这里是对案件的最小复制,带有最终解决方案。

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个数组的定义。我尝试使用reduce,但是语法非常丑陋。

有什么想法吗?

4 个答案:

答案 0 :(得分:0)

它并不短,但是我会选择一个更通用的函数,该函数根据给定的属性(在您的情况下为“ date”)和一些边界值(您有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);

请注意,如果您的数据可能具有未来日期,则需要将一个额外的边界设置为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)
, [[], [], []]);

答案 1 :(得分:0)

您可以将函数移到数组中并获取索引,以供以后推送该项目。

out = []

while len(l)>0:
    first, *rest = l
    first = set(first)

    lf = -1
    while len(first)>lf:
        lf = len(first)
        print(lf)
        rest2 = []
        for r in rest:
            if len(first.intersection(set(r)))>0:
                first |= set(r)
            else:
                rest2.append(r)     
        rest = rest2

    out.append(first)
    l = rest

答案 2 :(得分:0)

您想使下面的部分更简洁吗?

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)

答案 3 :(得分:0)

与其他大多数答案一样,这是使用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);