如何使用排除键数组实现JSON扁平化?
实现带排除键的JSON扁平化方案
嘿,这个需求很实用!我们可以通过在扁平化递归过程中,实时检查当前键的完整路径是否匹配排除规则,来精准跳过指定的层级键。下面是修改后的完整代码,包含详细的功能实现和注释:
// 可配置的排除键数组,支持层级路径(如"addresses.metadata")或顶层键(如"metadata") var exclusion_list = ["addresses.metadata", "pageToken", "metadata"]; var crowds = [{ "name": [{ "firstName": "John", "middleName": "Joseph", "lastName": "Briggs", }], "addresses": [{ "type": "home", "poBox": "111", "city": "City1", "postalCode": "1ER001", "country": "USA", "metadata": "要排除的地址元数据" // 这个会被排除 }, { "type": "work", "poBox": "222", "city": "City2", "region": "Region2", "postalCode": "1ER002", }], "photos": [{ "url": "photo.org/person1", "default": true, }, { "url": "imagur.org/person1", "default": true, }], "metadata": [{ "meta-id": "1234", // 顶层metadata会被排除 }], }, { "name": [{ "firstName": "Bill", "lastName": "Thatcher", }], "addresses": [{ "type": "home", "city": "City3", "region": "Region3", "postalCode": "1ER003", "country": "USA", }, { "type": "work", "poBox": "444", "region": "Region4", "postalCode": "1ER004", "metadata": "另一个要排除的地址元数据" // 这个也会被排除 }, { "poBox": "555", "region": "Region5", "postalCode": "1ER005", }], "metadata": [{ "meta-id": "1234", // 顶层metadata会被排除 }], }]; // 辅助函数:检查当前路径是否需要排除 function shouldExclude(currentKeyPath, exclusionList) { // 1. 把扁平化生成的路径格式(如"addresses #1: metadata")转换成标准层级格式("addresses.metadata") const normalizedPath = currentKeyPath .replace(/: /g, '.') // 把": "替换成"." .replace(/ #\d+/g, ''); // 去掉数组项的索引标记(如" #1") // 2. 检查是否匹配排除列表中的任意规则 return exclusionList.some(excludeRule => { // 排除规则支持精确层级匹配,比如"addresses.metadata"仅匹配addresses节点下的metadata return normalizedPath === excludeRule; }); } // 带排除功能的扁平化函数 function flatten(obj, exclusionList, res = {}, currentKey = '') { const addKeyPart = (delimiter, part) => currentKey ? `${currentKey}${delimiter}${part}` : part; if (Array.isArray(obj)) { // 处理数组:给每个项添加索引标记(如" #1") obj.forEach((item, index) => { const newKey = addKeyPart(' #', index + 1); flatten(item, exclusionList, res, newKey); }); } else if (typeof obj === 'object' && obj !== null) { // 处理对象:遍历每个键值对 Object.entries(obj).forEach(([key, value]) => { const newKey = addKeyPart(': ', key); // 检查当前键路径是否需要排除,不需要才继续处理 if (!shouldExclude(newKey, exclusionList)) { flatten(value, exclusionList, res, newKey); } }); } else { // 处理基础类型:添加到结果对象 res[currentKey] = obj; } return res; } // 生成扁平化后的数组 let flats = crowds.map(obj => flatten(obj, exclusion_list)); // 合并所有扁平化结果的键,生成表头 function combineKeys(objs) { let keys = objs.reduce((allKeys, obj) => allKeys.concat(Object.keys(obj)), []); return [...new Set(keys)]; // 去重 } let keys = combineKeys(flats); // 生成二维表格数组 let table = flats.map(flatObj => keys.map(key => flatObj[key] ?? '')); table.unshift(keys); // 添加表头 console.log({ table });
关键功能说明
排除规则的匹配逻辑
- 通过
shouldExclude函数,把扁平化过程中生成的路径(比如addresses #1: metadata)转换成和排除规则一致的格式(addresses.metadata),再进行精确匹配。 - 支持两种排除规则:
- 顶层键:比如
"metadata",会跳过所有顶层的metadata节点。 - 层级键:比如
"addresses.metadata",仅跳过addresses节点下的所有metadata子节点(不管是数组中的哪一项)。
- 顶层键:比如
- 通过
扁平化函数的改动
- 新增
exclusionList参数,让排除规则可以灵活配置。 - 在处理对象的键值对时,先检查当前路径是否需要排除,只有不需要排除的键才会继续递归处理。
- 新增
保持原有功能
- 保留了原代码中数组项的索引标记(如
name #1: firstName),确保数组展开后的结构清晰。 - 依然会生成包含表头的二维数组,适配动态JSON转表格的需求。
- 保留了原代码中数组项的索引标记(如
内容的提问来源于stack exchange,提问作者Code Guy
相关产品推荐
相关产品推荐

