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

修复JS对象数组按日期扁平化时缺失分类默认补0的问题

数据集扁平化转换问题修复方案

问题背景

需要将按日期、分类存储的明细数组,转换为按日期聚合的扁平化数组:每个日期对应一个对象,键包含日期字段、所有分类字段,分类字段值为对应KPI的数值,缺失分类数据时默认填充0。

原始数据结构

const CATEGORY = "category";
const DATE = "date";

const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
  { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

目标输出结构

const result = [
  { "date": "2012", "pizza": 1, "fruit": 3, "pasta": 2 },
  { "date": "2013", "pizza": 1, "fruit": 3, "pasta": 1 },
  { "date": "2014", "pizza": 2, "fruit": 2, "pasta": 1 }
]

核心问题

原有实现存在3个问题:

  • reduce逻辑以空对象为初始值,只会写入当前日期下实际存在的分类键,没有为全量分类预置默认值,因此缺失分类的键不会出现在结果中
  • 直接调用uniqBy/groupBy未加_前缀,在模块化引入lodash的场景会直接报错
  • datum[kpi] || 0的兜底逻辑存在风险:会将所有假值(包括合法的数值0)误判为缺失值替换

修复逻辑

  • 先提取全量分类列表,处理每个日期分组时,先生成基础对象:所有分类默认值为0,同时预置date字段
  • 遍历当前日期下的实际数据条目,覆盖对应分类的KPI值
  • 修正lodash方法调用,用严格空值判断替代||做兜底,避免误判合法数值0

修正后完整代码

import * as _ from 'lodash';

const CATEGORY = "category";
const DATE = "date";

function flatize(dataset, kpi) {
  // 获取全量分类列表
  const categories = _.uniqBy(dataset, CATEGORY).map((d) => d[CATEGORY]);
  // 按日期分组
  const groupByDate = _.groupBy(dataset, DATE);
  const dates = Object.keys(groupByDate);

  const flatizedDataset = dates.map((date) => {
    // 初始化当前日期的基础对象:所有分类默认填0,预置date字段
    const dateItem = {
      [DATE]: date,
      ...Object.fromEntries(categories.map(cat => [cat, 0]))
    };
    // 遍历当前日期下的实际数据,覆盖对应分类的kpi值
    groupByDate[date].forEach(datum => {
      dateItem[datum[CATEGORY]] = datum[kpi] ?? 0;
    });
    return dateItem;
  });

  return flatizedDataset;
}

// 测试用例:2012年缺失fruit分类
const dataset = [
  { date: "2012", category: "pizza", valueA: 1, valueB: 1, valueC: 3 },
  // { date: "2012", category: "fruit", valueA: 3, valueB: 3, valueC: 1 },
  { date: "2012", category: "pasta", valueA: 2, valueB: 2, valueC: 2 },
  { date: "2013", category: "pizza", valueA: 1, valueB: 2, valueC: 2 },
  { date: "2013", category: "fruit", valueA: 3, valueB: 2, valueC: 3 },
  { date: "2013", category: "pasta", valueA: 1, valueB: 3, valueC: 1 },
  { date: "2014", category: "pizza", valueA: 2, valueB: 1, valueC: 2 },
  { date: "2014", category: "fruit", valueA: 2, valueB: 2, valueC: 0 },
  { date: "2014", category: "pasta", valueA: 1, valueB: 3, valueC: 1 }
];

const flatDataset = flatize(dataset, "valueA");
console.log(flatDataset);
/*
输出结果符合预期,缺失分类自动填充0:
[
  { date: '2012', pizza: 1, fruit: 0, pasta: 2 },
  { date: '2013', pizza: 1, fruit: 3, pasta: 1 },
  { date: '2014', pizza: 2, fruit: 2, pasta: 1 }
]
*/

低版本环境兼容

如果运行环境不支持Object.fromEntries和??空值合并运算符,可以替换为lodash方法实现:

const flatizedDataset = dates.map((date) => {
  // 替换基础对象生成逻辑
  const dateItem = _.reduce(categories, (acc, cat) => {
    acc[cat] = 0;
    return acc;
  }, { [DATE]: date });
  // 替换赋值兜底逻辑
  groupByDate[date].forEach(datum => {
    dateItem[datum[CATEGORY]] = _.isNil(datum[kpi]) ? 0 : datum[kpi];
  });
  return dateItem;
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:45:36