TypeScript 中含动态元素的对象数组如何按键提取全部唯一值
TypeScript 动态无Schema对象数组的键值聚合去重实现
需求与场景
- 输入为无固定Schema约束的对象数组,数组元素的顶层键(如
Value1/Value2)、键对应的字符串值(如name/age)均为动态生成,无固定类型约束 - 目标输出为聚合对象:属性为原数组元素的顶层键,属性值为对应键下所有出现过的字符串值去重后的数组
- 此前使用
array.reduce()实现未得到预期效果,以下为适配动态键场景的可行方案
Reduce实现常见失败原因
- 未显式指定
reduce的初始值:默认取数组第一个元素作为初始值,导致类型不匹配、逻辑错乱 - 硬编码访问固定键:未遍历当前对象的所有动态键,导致运行时新增的动态键被遗漏
- 未做去重直接push值:结果中残留同键的重复值
基础实现(中小数据量适用)
类型定义
// 原始输入元素类型:任意字符串键对应字符串值 type DynamicObject = Record<string, string>; // 聚合结果类型 type AggregatedResult = Record<string, string[]>;
完整实现代码
// 示例输入数组(模拟动态生成的无Schema结构) const inputArray: DynamicObject[] = [ { Value1: "name", Value2: "surname" }, { Value1: "age", Value3: "hoursWorked" }, { Value2: "surname", Value3: "hoursWorked" }, { Value1: "name" }, ]; const aggregatedResult = inputArray.reduce<AggregatedResult>((acc, currObj) => { // 遍历当前对象的所有动态顶层键 Object.keys(currObj).forEach((key) => { const currentValue = currObj[key]; // 首次出现该键时初始化对应数组 if (!acc[key]) acc[key] = []; // 去重判断:仅当前值不存在时才插入 if (!acc[key].includes(currentValue)) acc[key].push(currentValue); }); return acc; }, {}); // 必须显式传入空对象作为初始值
输出示例
{ Value1: ["name", "age"], Value2: ["surname"], Value3: ["hoursWorked"] }
性能优化实现(大数据量适用)
当数组长度较大、单键下唯一值较多时,使用Set的自动去重特性可降低查询的时间复杂度:
// 中间层用Map存储键和对应Set,避免O(n)的includes查询 const tempMap = inputArray.reduce<Map<string, Set<string>>>((acc, currObj) => { Object.entries(currObj).forEach(([key, value]) => { if (!acc.has(key)) acc.set(key, new Set()); // Set自动去重,无需手动判断重复 acc.get(key)!.add(value); }); return acc; }, new Map()); // 转换为要求的最终对象格式 const finalResult: AggregatedResult = Object.fromEntries( Array.from(tempMap.entries()).map(([key, valueSet]) => [key, Array.from(valueSet)]) );
内容的提问来源于stack exchange,提问作者user1234567
相关产品推荐
相关产品推荐

