如何用JavaScript统计歌曲子流派频次并更新流派数组对象
统计子流派出现次数并更新流派映射数组
问题背景
现有歌曲数组songs,每个歌曲包含多个子流派;还有手动维护的流派映射数组genres,记录父流派与子流派的对应关系。需要统计每个子流派在歌曲中的出现次数,并给genres里对应的子流派添加size属性。
歌曲数组示例:
const songs = [ { track_name: "name of track" , track_genres: ["chamber pop","indie pop"] }, { track_name: "name of track 2" , track_genres: ["dutch r&b","indie soul", "indie pop"] }, { track_name: "name of track 3" , track_genres: ["indie pop","chamber pop","indie soul"] } ];
流派映射数组示例:
const genres = [ { name: "Pop", children: [{name:"Chamber Pop"},{name:"Indie Pop"}] }, { name: "R&B", children: [{name:"Dutch R&B"}] }, { name: "Soul", children: [{name:"Indie Soul"}] } ];
理想输出:
// 更新后的genres [ { name: "Pop", children: [{name:"Chamber Pop", size:2},{name:"Indie Pop", size:3}] }, { name: "R&B", children: [{name:"Dutch R&B", size:1}] }, { name: "Soul", children: [{name:"Indie Soul", size:2}] } ];
解决方案
1. 原生JavaScript实现
核心思路是先建立子流派名称到对应对象的映射,避免反复遍历genres查找,提升效率:
// 1. 建立子流派名称到对应对象的映射表(统一大小写避免匹配误差) const genreMap = new Map(); genres.forEach(parent => { parent.children.forEach(child => { const normalizedName = child.name.toLowerCase(); genreMap.set(normalizedName, child); }); }); // 2. 统计所有子流派的出现次数 const countMap = new Map(); songs.forEach(song => { song.track_genres.forEach(genre => { const normalized = genre.toLowerCase(); countMap.set(normalized, (countMap.get(normalized) || 0) + 1); }); }); // 3. 给genres里的子流派添加size属性 genreMap.forEach((child, name) => { child.size = countMap.get(name) || 0; }); console.log(genres); // 得到理想输出
2. Lodash简化实现
利用Lodash的数组和集合工具函数,代码更简洁:
const _ = require('lodash'); // 提取所有歌曲里的子流派并统计次数 const genreCounts = _.countBy( _.flatMap(songs, 'track_genres'), g => g.toLowerCase() ); // 遍历genres更新size属性 _.forEach(genres, parent => { _.forEach(parent.children, child => { const normalized = child.name.toLowerCase(); child.size = genreCounts[normalized] || 0; }); }); console.log(genres);
内容的提问来源于stack exchange,提问作者NNS
相关产品推荐
相关产品推荐

