如何动态过滤对象数组,按语言提取城市计数至新结构?
动态城市场景下按语言过滤提取城市count值的实现方案
问题描述
静态场景实现
初始输入数据(固定城市为usa和japan):
[ { "metadata": { "id": 1071, "name": "First" }, "languages": [ { "name": "Alpha", "details": [ { "city": "usa", "count": 33 } ] }, { "name": "Beta", "details": [ { "city": "japan", "count": 3 } ] } ] }, { "metadata": { "id": 1068, "name": "Second" }, "languages": [ { "name": "Alpha", "details": [ { "city": "japan", "count": 10 }, { "city": "usa", "count": 20 } ] }, { "name": "Beta", "details": [ { "city": "japan", "count": 15 }, { "city": "usa", "count": 25 } ] } ] } ]
需求:按指定语言过滤,提取对应语言下各城市的count值,生成如下结构结果:
// 过滤Alpha时 output = { japan: [0, 10], usa: [33, 20] } // 过滤Beta时 output = { japan: [3, 15], usa: [0, 25] }
已实现的静态场景代码:
const filterBy = (data, name) => { return data.reduce((p, c) => { for (let langObj of c.languages) { if (langObj.name === name) { const groupedOnCityCount = langObj.details.reduce((x, {city,count}) => ({ ...x, [city]: count }), {}); p.usa.push(groupedOnCityCount?.usa || 0); p.japan.push(groupedOnCityCount?.japan || 0); } } return p; }, { japan: [], usa: [] }); } const A = filterBy(data, 'Alpha'); const B = filterBy(data, 'Beta');
动态场景需求
现在输入变为动态:城市不固定(可能新增),部分语言的details数组可能为空,示例动态输入:
[ { "metadata": { "id": 1071, "name": "First" }, "languages": [ { "name": "Alpha", "details": [ { "city": "usa", "count": 33 }, { "city": "korea", "count": 20 } ] }, { "name": "Beta", "details": [ { "city": "japan", "count": 3 } ] } ] }, { "metadata": { "id": 1068, "name": "Second" }, "languages": [ { "name": "Alpha", "details": [] }, { "name": "Beta", "details": [ { "city": "japan", "count": 15 }, { "city": "russia", "count": 77 } ] } ] } ]
需要生成动态结果:
// 过滤Alpha时 output = { usa: [33, 0], korea: [20, 0 ] } // 过滤Beta时 output = { japan: [3, 15], russia: [0, 77] }
修改后的实现代码
const filterBy = (data, name) => { // 收集目标语言下所有出现过的城市,避免遗漏 const allCities = new Set(); data.forEach(item => { const targetLang = item.languages.find(lang => lang.name === name); if (targetLang?.details) { targetLang.details.forEach(detail => allCities.add(detail.city)); } }); // 初始化结果对象,每个城市对应一个空数组 const result = [...allCities].reduce((acc, city) => { acc[city] = []; return acc; }, {}); // 遍历每个数据项,填充对应城市的count值(无则补0) data.forEach(item => { const targetLang = item.languages.find(lang => lang.name === name); // 将当前项的details转为城市-计数的映射,空details则返回空对象 const cityCountMap = targetLang?.details?.reduce((map, { city, count }) => { map[city] = count; return map; }, {}) || {}; // 对每个已收集的城市,push对应值或0 [...allCities].forEach(city => { result[city].push(cityCountMap[city] || 0); }); }); return result; } // 测试示例 const dynamicData = [ { "metadata": { "id": 1071, "name": "First" }, "languages": [ { "name": "Alpha", "details": [ { "city": "usa", "count": 33 }, { "city": "korea", "count": 20 } ] }, { "name": "Beta", "details": [ { "city": "japan", "count": 3 } ] } ] }, { "metadata": { "id": 1068, "name": "Second" }, "languages": [ { "name": "Alpha", "details": [] }, { "name": "Beta", "details": [ { "city": "japan", "count": 15 }, { "city": "russia", "count": 77 } ] } ] } ]; const alphaResult = filterBy(dynamicData, 'Alpha'); const betaResult = filterBy(dynamicData, 'Beta'); console.log(alphaResult); // { usa: [33, 0], korea: [20, 0] } console.log(betaResult); // { japan: [3, 15], russia: [0, 77] }
关键思路说明
- 动态收集城市:先遍历所有数据项,提取目标语言下出现的所有城市,用
Set去重,确保不管新增什么城市都能被捕获。 - 初始化结果结构:基于收集到的城市列表,初始化每个城市对应空数组的结果对象。
- 填充计数数据:遍历每个数据项,将当前项的
details转为城市-计数的映射,然后对每个已收集的城市,取对应计数或补0,推入结果数组中。 - 兼容空details:当目标语言的
details为空时,cityCountMap会是一个空对象,此时所有城市都会补0,符合需求。
内容的提问来源于stack exchange,提问作者Aren Trot
相关产品推荐
相关产品推荐

