代码之家  ›  专栏  ›  技术社区  ›  Maryannah

在给定条件下,将一个项数组拆分为多个数组

  •  0
  • Maryannah  · 技术社区  · 5 年前

    问题很简单:我有一系列物品,都有日期。根据日期,我想把这个数组分成几个数组。

    在我的例子中,我想将数组分成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,但是语法很难看。

    有什么想法吗?

    0 回复  |  直到 5 年前
        1
  •  0
  •   trincot    5 年前

    它并不短,但我会使用一个更通用的函数,该函数根据给定的属性(“日期”在您的情况下)和一些边界值(您有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)
    , [[], [], []]);
    
        2
  •  0
  •   Nina Scholz    5 年前

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

    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);
        3
  •  0
  •   wang    5 年前

    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)
        4
  •  0
  •   3limin4t0r    5 年前

    map 而不是 reduce

    这只是通过比较日期,删除 item 如果符合特定条件,则从数组中删除。在下面的例子中,我复制了数组 arr 完整的。但是如果你不在乎的话你可以忽略这个 变异,或者你想看看哪些项目不符合任何标准(因为它们被留下了)。

    reverseEach 功能显而易见。如果我开始从当前正在元素上迭代的数组中删除项,则开始移动。从后到前迭代时,这无关紧要,因为我已经处理过这些项。

    在下面的例子中,顺序很重要。当你把 t1w (时间1周)作为数组中的第一个元素 阿里尔

    // 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);