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

使用Lodash与Reduce重塑JSON时日期分组数据缺失问题排查

问题分析:按日期分组后数据不全的原因及修复方案

问题现象

你通过csvtojson解析CSV后,用reduce按日期分组时发现2020-06-29只返回了1条数据,而实际应该包含多个时间点的监测数据——整体JSON结构符合预期,但数据缺失严重。

问题根源

看你写的reduce逻辑:

const res = json_from_csv_filtered.reduce((acc, val) => {
 const find = acc.find(el => el.date === val.datetime.substring(0, 10));
 const { datetime, ...obj } = val;
 if (find) {
 find.values[0] = { ...find.values[0], ...obj };
 } else {
 acc.push({ date: datetime.substring(0, 10), values: [{ t: datetime, ...obj }] });
 }
 return acc;
}, []);

核心问题出在这里:同一日期下,你始终把新的污染物数据合并到values数组的第一个元素里,完全忽略了时间点(t)的差异。

举个实际场景的例子:假设2020-06-29有两个时间点(00:59和01:59)的监测数据:

  1. 处理00:59的Benzene时,代码会创建日期分组,values里新增{t: "2020-06-29T00:59:59.000Z", Benzene:4.3}
  2. 处理00:59的NO2和O3时,会合并到这个第一个元素里,得到完整的00:59时间点数据
  3. 处理01:59的Benzene时,代码直接把这个值合并到values[0]里,覆盖掉原来的Benzene值,同时01:59这个时间点的记录完全丢失

最终就导致同一日期下只能保留第一个被处理的时间点数据,其他时间点的污染物都会被“合并覆盖”,时间点本身不会新增。

修复方案

需要在同一日期下,再按时间点(t)进行二次分组:找到日期对应的分组后,先在values里查找是否有相同t的对象,有就合并污染物,没有就新增一条values项。修改后的reduce代码如下:

const res = json_from_csv_filtered.reduce((acc, val) => {
  const dateStr = val.datetime.substring(0, 10);
  const { datetime, ...obj } = val;
  // 先查找对应日期的分组
  const dateGroup = acc.find(el => el.date === dateStr);
  
  if (dateGroup) {
    // 在日期分组内查找对应时间点的记录
    const timePoint = dateGroup.values.find(item => item.t === datetime);
    if (timePoint) {
      // 已有该时间点,合并污染物数据
      Object.assign(timePoint, obj);
    } else {
      // 无该时间点,新增一条记录
      dateGroup.values.push({ t: datetime, ...obj });
    }
  } else {
    // 无该日期分组,新建分组并添加第一个时间点记录
    acc.push({ 
      date: dateStr, 
      values: [{ t: datetime, ...obj }] 
    });
  }
  return acc;
}, []);

额外优化建议

考虑到你已经引入了Lodash,可以用_.find替代原生Array.find提升查找性能:

// 替换原有的dateGroup查找逻辑
const dateGroup = _.find(acc, { date: dateStr });

如果CSV数据量较大,原生数组find的性能会明显下降,建议用临时对象存储分组数据,最后再转成目标数组结构,性能会好很多:

// 用对象临时存储按日期+时间点分组的数据
const tempMap = json_from_csv_filtered.reduce((map, val) => {
  const dateStr = val.datetime.substring(0, 10);
  const { datetime, ...obj } = val;
  // 按日期建一级键
  if (!map[dateStr]) map[dateStr] = {};
  // 按时间点建二级键
  if (!map[dateStr][datetime]) {
    map[dateStr][datetime] = { t: datetime };
  }
  // 合并当前污染物数据
  Object.assign(map[dateStr][datetime], obj);
  return map;
}, {});

// 把临时对象转成预期的数组结构
const res = Object.entries(tempMap).map(([date, timePoints]) => ({
  date,
  values: Object.values(timePoints)
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:37:55