如何将JavaScript对象数组转换为列式HTML表格(行转列)
问题描述
我有如下JavaScript对象数组(注:原始数据为PHP风格对象,转成JS对象后结构如下):
const response = [ { id: 12951, user_id: 1, balance_amt: 100, year: 2020, username: 'User1' }, { id: 11751, user_id: 2, balance_amt: 100, year: 2020, username: 'User2' }, { id: 12816, user_id: 1, balance_amt: 100, year: 2021, username: 'User1' }, { id: 11014, user_id: 3, balance_amt: 0, year: 2020, username: 'User3' }, { id: 11817, user_id: 2, balance_amt: 100, year: 2021, username: 'User2' }, { id: 12466, user_id: 3, balance_amt: 100, year: 2021, username: 'User3' }, { id: 10664, user_id: 3, balance_amt: 0, year: 2022, username: 'User3' }, { id: 8944, user_id: 3, balance_amt: 100, year: 2023, username: 'User3' }, { id: 7269, user_id: 1, balance_amt: 0, year: 2022, username: 'User1' }, { id: 5632, user_id: 2, balance_amt: 0, year: 2022, username: 'User2' }, { id: 4034, user_id: 3, balance_amt: 0, year: 2024, username: 'User3' }, { id: 2476, user_id: 2, balance_amt: 0, year: 2023, username: 'User2' } ];
当前展示的行式结构表格:
| Username | year | Balance |
|---|---|---|
| User1 | 2020 | 100 |
| User1 | 2021 | 100 |
| User1 | 2022 | 0 |
| User2 | 2020 | 100 |
| User2 | 2021 | 100 |
| User2 | 2022 | 0 |
| User2 | 2023 | 0 |
| User3 | 2020 | 0 |
| User3 | 2021 | 100 |
| User3 | 2022 | 0 |
| User3 | 2023 | 100 |
| User3 | 2024 | 0 |
我需要将其转为列式结构,年份作为表头,每个用户一行展示各年份余额,无数据的填-:
| Username | 2020 | 2021 | 2022 | 2023 | 2024 |
|---|---|---|---|---|---|
| User1 | 100 | 100 | 0 | - | - |
| User2 | 100 | 100 | 0 | 0 | - |
| User3 | 0 | 100 | 0 | 100 | 0 |
尝试了以下代码但未得到预期结果,求解决:
response.reduce((a2, c2) => { let filteredP = a2.filter(el => el.year === c2.year) if (filteredP.length > 0) { a2[a2.indexOf(filteredP[0])].balance_amt += +c2.balance_amt; } else { a2.push(c2); } return a2; }, []);
解决方案
你的代码逻辑是按年份合并余额,但我们需要的是按用户分组,同时整理各年份的余额数据,可以分两步实现:
步骤1:按用户分组,收集每个用户的年份-余额映射
先用reduce把数据整理成以用户名为键的对象,每个用户对应一个记录各年份余额的对象:
// 按用户分组,收集各年份余额 const userBalances = response.reduce((acc, item) => { const { username, year, balance_amt } = item; if (!acc[username]) { acc[username] = { username }; } // 给当前用户的对应年份赋值余额 acc[username][year] = balance_amt; return acc; }, {});
步骤2:提取所有唯一年份,生成目标结构数据
先找出所有存在的年份并排序,再遍历每个用户的分组数据,补全年份缺失的部分(用-填充):
// 获取所有唯一年份并排序 const allYears = [...new Set(response.map(item => item.year))].sort((a, b) => a - b); // 生成最终表格数据 const tableData = Object.values(userBalances).map(user => { const row = { username: user.username }; allYears.forEach(year => { row[year] = user[year] !== undefined ? user[year] : '-'; }); return row; });
最终结果
得到的tableData结构完全匹配目标表格需求:
[ { username: 'User1', 2020: 100, 2021: 100, 2022: 0, 2023: '-', 2024: '-' }, { username: 'User2', 2020: 100, 2021: 100, 2022: 0, 2023: 0, 2024: '-' }, { username: 'User3', 2020: 0, 2021: 100, 2022: 0, 2023: 100, 2024: 0 } ]
逻辑说明
- 第一步通过
reduce按用户名分组,把每个用户的各年份余额直接存入对应对象的属性中; - 第二步提取所有年份并排序,保证表头顺序正确;
- 最后遍历分组后的用户数据,对每个年份检查是否有余额,无数据则填充
-,生成符合要求的行数据。
内容的提问来源于stack exchange,提问作者Mohammed
相关产品推荐
相关产品推荐

