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

如何高效计算过去12个月各账户的最高及最低余额?

优化方案:解决过去12个月账户余额极值计算的超时问题

原代码的性能瓶颈

  1. 低效的月份查找:遍历每笔交易时用months.find()匹配年月,每次查找都是O(13)的遍历,交易量大时累计开销很高
  2. 重复创建Date对象:处理交易日期、排序时多次调用new Date(),造成不必要的性能损耗
  3. 冗余的余额存储与计算:先把所有余额存入数组,再遍历数组计算最大最小值,多了一次完整遍历
  4. 排序逻辑冗余:排序回调里每次比较都创建新的Date实例,排序效率低

高效实现思路

  1. 用Map替代数组查找:以YYYY-MM格式字符串为键存储月份统计数据,查找月份的时间复杂度降为O(1)
  2. 预计算目标年月范围:提前生成过去13个月的YYYY-MM键集合,快速判断交易是否在目标范围内
  3. 一次遍历完成双重任务:遍历交易时同步维护对应月份的最大、最小余额,无需额外存储所有余额数据
  4. 优化排序逻辑:先将交易日期转换为时间戳,排序时直接比较数字,避免重复创建Date对象

优化后的代码

exports.main = async({ accounts, transactions }) => {
  const currentDate = new Date();
  const currentYear = currentDate.getFullYear();
  const currentMonth = currentDate.getMonth();

  // 预生成过去13个月的映射关系与基础数据
  const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
  const monthMap = new Map();
  const targetMonths = [];

  for (let i = 0; i < 13; i++) {
    const date = new Date(currentYear, currentMonth - i, 1);
    const year = date.getFullYear();
    const monthIdx = date.getMonth();
    const key = `${year}-${String(monthIdx + 1).padStart(2, '0')}`;
    const monthData = {
      monthName: monthNames[monthIdx],
      yearName: year,
      highestUtilisation: -Infinity,
      lowestUtilisation: Infinity,
      hasData: false
    };
    monthMap.set(key, monthData);
    targetMonths.push(monthData);
  }

  // 计算初始总余额
  const currentBalance = accounts.reduce((total, acc) => total + acc.balance.current, 0);

  // 优化排序:提前转换时间戳,避免重复创建Date
  transactions.sort((a, b) => {
    return new Date(b.postedDate).getTime() - new Date(a.postedDate).getTime();
  });

  let runningBalance = currentBalance;

  // 遍历交易,同步更新余额与月份极值
  for (const tr of transactions) {
    if (tr.amount !== 0) {
      runningBalance += tr.amount;
    }

    // 快速提取交易的YYYY-MM键(假设postedDate格式为"YYYY-MM-DD...")
    const key = tr.postedDate.slice(0, 7);
    const monthData = monthMap.get(key);
    if (!monthData) continue;

    monthData.hasData = true;
    // 更新当前月份的最大、最小余额
    if (runningBalance > monthData.highestUtilisation) {
      monthData.highestUtilisation = runningBalance;
    }
    if (runningBalance < monthData.lowestUtilisation) {
      monthData.lowestUtilisation = runningBalance;
    }
  }

  // 处理无数据月份,格式化数值
  targetMonths.forEach(month => {
    if (month.hasData) {
      month.highestUtilisation = Math.round(month.highestUtilisation * 100) / 100;
      month.lowestUtilisation = Math.round(month.lowestUtilisation * 100) / 100;
    } else {
      month.highestUtilisation = null;
      month.lowestUtilisation = null;
    }
    delete month.hasData;
  });

  // 返回过去12个完整月份
  return { months: targetMonths.slice(1) };
};

额外优化建议

  • 如果交易本身已按时间倒序存储,直接跳过排序步骤,节省排序开销
  • 若postedDate格式固定,优先用字符串截取提取年月,完全避免new Date()的调用开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:05:05