You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript/RXJS中实现带日期序列的7天滑动累计与均值计算

方案1:纯Reducer实现(无依赖)

和你原有固定周统计的reducer使用方式完全兼容,可直接用于数组reduce调用,也可嵌入RxJS的scan操作符中使用。累加器会缓存最近7天的原始数据和增量总和,滑动时仅做增减计算,无需全量遍历窗口,性能更好。

const sliding7dReducer = (accumulator, currentValue, index) => {
  // 首次调用初始化累加器结构
  if (!accumulator.window) {
    accumulator = {
      window: [], // 缓存当前窗口内的原始数据
      sumTemp: 0, // temp累计值
      sumHum: 0, // hum累计值
      results: [] // 存储每个位置的滑动计算结果
    }
  }

  // 加入当前值到窗口,更新总和
  accumulator.window.push(currentValue)
  accumulator.sumTemp += currentValue.temp
  accumulator.sumHum += currentValue.hum

  // 窗口超过7天则移除最早的元素,扣减对应总和
  if (accumulator.window.length > 7) {
    const removed = accumulator.window.shift()
    accumulator.sumTemp -= removed.temp
    accumulator.sumHum -= removed.hum
  }

  // 计算当前窗口的平均值,存入结果集
  const windowSize = accumulator.window.length
  accumulator.results.push({
    endDate: currentValue.date,
    windowSize,
    sumTemp: accumulator.sumTemp,
    sumHum: accumulator.sumHum,
    avgTemp: Number((accumulator.sumTemp / windowSize).toFixed(2)),
    avgHum: Number((accumulator.sumHum / windowSize).toFixed(2))
  })

  return accumulator
}

使用示例:

// measurements为你的测量值数组
const slidingResult = measurements.reduce(sliding7dReducer, {}).results

方案2:RxJS原生操作符实现(推荐,适配Observable场景)

针对你使用Observable的场景,直接用RxJS内置操作符实现更简洁,不需要手动维护reducer状态。

情况1:仅输出满7天的窗口结果

使用bufferCount操作符直接生成滑动窗口,第一个结果会在第7个数据推送后输出:

import { bufferCount, map } from 'rxjs/operators'

// measurements$为你的测量值Observable
const slidingResult$ = measurements$.pipe(
  bufferCount(7, 1), // 窗口大小7,每次滑动步长1
  map(window => {
    const sumTemp = window.reduce((sum, item) => sum + item.temp, 0)
    const sumHum = window.reduce((sum, item) => sum + item.hum, 0)
    return {
      endDate: window[6].date,
      windowSize: 7,
      sumTemp,
      sumHum,
      avgTemp: Number((sumTemp / 7).toFixed(2)),
      avgHum: Number((sumHum / 7).toFixed(2))
    }
  })
)

情况2:保留前6个不满7天的窗口结果

用scan操作符实现和方案1一致的逻辑,从第一个数据开始就输出结果:

import { scan, map } from 'rxjs/operators'

const slidingResult$ = measurements$.pipe(
  scan((acc, current) => {
    acc.window.push(current)
    acc.sumTemp += current.temp
    acc.sumHum += current.hum
    if (acc.window.length > 7) {
      const removed = acc.window.shift()
      acc.sumTemp -= removed.temp
      acc.sumHum -= removed.hum
    }
    const windowSize = acc.window.length
    return {
      window: acc.window,
      sumTemp: acc.sumTemp,
      sumHum: acc.sumHum,
      result: {
        endDate: current.date,
        windowSize,
        sumTemp: acc.sumTemp,
        sumHum: acc.sumHum,
        avgTemp: Number((acc.sumTemp / windowSize).toFixed(2)),
        avgHum: Number((acc.sumHum / windowSize).toFixed(2))
      }
    }
  }, { window: [], sumTemp: 0, sumHum: 0 }),
  map(acc => acc.result)
)

补充说明

如果你的测量数据存在日期断档,不是按天连续推送,可以把窗口长度判断替换为日期差校验,仅保留当前日期往前7天内的有效数据即可,核心逻辑和上面的实现一致。

内容的提问来源于stack exchange,提问作者stwissel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 18:24:06