TypeScript如何合并对象数组中关联状态数组生成新数组?
问题描述
现有如下TypeScript数组:
const books = [ { name: 'book1', id: '1', fromStatus: [ { name: 'Available', id: 1 }, { name: 'Free', id: 2 } ], toStatus: [ { name: 'Not available', id: 1 }, { name: 'Not free', id: 2 } ] }, { name: 'book2', id: '2', fromStatus: [{ name: 'Burnt', id: 1 }], toStatus: [{ name: 'Not burnt', id: 1 }] } ];
需要生成新数组,根据id匹配每个fromStatus和对应的toStatus,整合为包含id、fromStatusName、toStatusName的新对象,目标数组如下:
const statusFromTo = [ { id: 1, fromStatusName: 'Available', toStatusName: 'Not available' }, { id: 2, fromStatusName: 'Burnt', toStatusName: 'Not burnt' }, { id: 3, fromStatusName: 'Free', toStatusName: 'Not free' } ];
解决方案
可以通过状态映射收集+数组转换的方式实现,代码如下:
// 收集所有状态的映射关系,避免重复 const statusMap = new Map<number, { fromName: string; toName: string }>(); books.forEach(book => { // 把当前书籍的toStatus转成id到名称的映射,方便快速查找 const toStatusMap = book.toStatus.reduce((acc, status) => { acc[status.id] = status.name; return acc; }, {} as Record<number, string>); // 遍历fromStatus,匹配对应的toStatus名称 book.fromStatus.forEach(fromStatus => { const targetToName = toStatusMap[fromStatus.id]; if (targetToName) { statusMap.set(fromStatus.id, { fromName: fromStatus.name, toName: targetToName }); } }); }); // 转换为目标数组,生成自增的新id const statusFromTo = Array.from(statusMap.entries()).map(([_, names], index) => ({ id: index + 1, fromStatusName: names.fromName, toStatusName: names.toName }));
逻辑说明
- 遍历每本书,先把当前书的
toStatus转换为以id为键、状态名为值的对象,这样可以通过id直接获取对应的目标状态名,避免嵌套循环查找。 - 遍历当前书的
fromStatus,通过id从上面的映射中拿到对应的toStatus名称,存入Map中(如果有相同原始id的状态,会自动去重)。 - 最后把
Map中的内容转为数组,同时生成自增的新id,结构化成目标格式。
如果不需要去重(允许相同原始id的状态重复出现在结果中),可以直接收集数组:
const statusFromTo: { id: number; fromStatusName: string; toStatusName: string }[] = []; books.forEach(book => { const toStatusMap = book.toStatus.reduce((acc, status) => { acc[status.id] = status.name; return acc; }, {} as Record<number, string>); book.fromStatus.forEach(fromStatus => { const targetToName = toStatusMap[fromStatus.id]; if (targetToName) { statusFromTo.push({ id: statusFromTo.length + 1, fromStatusName: fromStatus.name, toStatusName: targetToName }); } }); });
内容的提问来源于stack exchange,提问作者cking888
相关产品推荐
相关产品推荐

