如何遍历JSON数据生成按州统计水果数量的指定数据结构
按州分组统计水果数量的实现方案
需求说明
需要遍历给定的JSON数据,按州分组统计每种水果的数量,生成包含州名和对应水果统计数组的对象数组。
原始数据
const data = [ { "State": "California", "Fruits": [{"name": "oranges", "code": "112"}, {"name": "apple", "code": "111"}] }, { "State": "Arizona", "Fruits": [{"name": "oranges", "code": "112"}, {"name": "apple", "code": "111"}, {"name": "kiwi", "code": "999"}] }, { "State": "Ohio", "Fruits": [{"name": "oranges", "code": "112"}, {"name": "kiwi", "code": "999"}] }, { "State": "Arizona", "Fruits": [{"name": "kiwi", "code": "999"}] }, { "State": "California", "Fruits": [{"name": "oranges", "code": "112"}, {"name": "apple", "code": "111"}, {"name": "kiwi", "code": "999"}] }, { "State": "Arizona", "Fruits": [{"name": "oranges", "code": "112"}, {"name": "apple", "code": "111"}] } ];
期望输出
[ { State: 'California', Fruits: [ { name: 'Apples', count: 2 }, { name: 'Oranges', count: 2 }, { name: 'Kiwi', count: 1 } ] }, { State: 'Arizona', Fruits: [ { name: 'Apples', count: 2 }, { name: 'Oranges', count: 2 }, { name: 'Kiwi', count: 2 } ] }, { State: 'Ohio', Fruits: [ { name: 'Oranges', count: 1 }, { name: 'Kiwi', count: 1 } ] } ];
当前问题代码
当前代码仅能统计全局水果总数,无法按州分组:
let obj = {}; for(let i=0; i<data.length; i++){ for(let j=0; j<data[i].fruits.length; j++){ obj[data[i].fruits[j].name]? obj[data[i].fruits[j].name]++ : obj[data[i].fruits[j].name]=1; } }
输出结果:
{ "apple": 4, "oranges": 5, "kiwi": 4 }
修改后的实现代码
循环版本
// 中间对象,按州存储水果计数 const stateFruitCounts = {}; for (let i = 0; i < data.length; i++) { const currentState = data[i].State; const currentFruits = data[i].Fruits; // 如果当前州未初始化,创建空对象存储水果计数 if (!stateFruitCounts[currentState]) { stateFruitCounts[currentState] = {}; } // 遍历当前州的水果,更新计数 for (let j = 0; j < currentFruits.length; j++) { const fruitName = currentFruits[j].name; // 计数累加,不存在则初始化为1 stateFruitCounts[currentState][fruitName] = (stateFruitCounts[currentState][fruitName] || 0) + 1; } } // 转换为期望的数组格式 const result = Object.entries(stateFruitCounts).map(([state, counts]) => { return { State: state, Fruits: Object.entries(counts).map(([name, count]) => { // 处理水果名称首字母大写,复数形式(如apple→Apples) const formattedName = name.charAt(0).toUpperCase() + name.slice(1) + (name !== 'kiwi' ? 's' : ''); return { name: formattedName, count }; }) }; }); console.log(result);
简化版(使用reduce)
如果想更简洁,可以用Array.reduce实现:
const result = Object.values(data.reduce((acc, item) => { const state = item.State; // 初始化当前州的统计对象 if (!acc[state]) { acc[state] = { State: state, fruitCounts: {} }; } // 累加水果计数 item.Fruits.forEach(fruit => { acc[state].fruitCounts[fruit.name] = (acc[state].fruitCounts[fruit.name] || 0) + 1; }); return acc; }, {})).map(item => { // 转换为期望的Fruits数组格式 return { ...item, Fruits: Object.entries(item.fruitCounts).map(([name, count]) => { const formattedName = name.charAt(0).toUpperCase() + name.slice(1) + (name !== 'kiwi' ? 's' : ''); return { name: formattedName, count }; }) }; }); console.log(result);
代码说明
- 分组统计:通过中间对象
stateFruitCounts按州名作为键,存储每个州的水果计数,解决了原代码全局统计的问题。 - 格式转换:最后将中间对象的键值对转换为数组,并处理水果名称的格式(首字母大写、复数形式),匹配期望输出。
- 细节修正:原代码中
data[i].fruits应为data[i].Fruits(注意大小写),这也是原代码可能报错的点。
内容的提问来源于stack exchange,提问作者grooot
相关产品推荐
相关产品推荐

