JS遍历对象数组统计语言频次返回Top N结果实现方法
问题背景
需要实现mostSpokenLanguages函数,接收两个参数:存储国家信息的对象数组、数值n。功能是统计所有国家的语言出现次数,返回出现频次最高的前n种语言,返回格式为包含语言名称、对应计数字段的对象数组。
之前尝试用双层嵌套循环实现,卡在语言计数的核心逻辑,无法完成功能。
使用的国家数据结构示例:
const countries = [ { name: 'Afghanistan', capital: 'Kabul', languages: ['Pashto', 'Uzbek', 'Turkmen'], population: 27657145, currency: 'Afghan afghani' }, // ... 其他国家对象,languages字段为当前国家使用的语言数组,其余字段不影响统计逻辑 ]
预期输出格式:
console.log(mostSpokenLanguages(countries, 5)) /* [ {country: 'English',count:91}, {country: 'French',count:45}, {country: 'Arabic',count:25}, {country: 'Spanish',count:24}, {country:'Russian',count:9} ] */
原有未完成代码的核心问题:
- 遍历到语言时直接向结果数组插入新对象,没有判断该语言是否已经统计过,会生成大量重复的语言记录
- 尝试匹配已统计语言时,错误使用内层语言循环的索引查询结果数组,索引无法对应
- 统计完成后没有做频次排序,且
slice参数错误:slice(count)是从索引count位置截取到数组末尾,无法获取前n条最高频结果
符合原有双层循环思路的实现方案
完全沿用一开始的双层循环逻辑,只补全计数、排序、截取的正确逻辑,代码如下:
const mostSpokenLanguages = (arr, n) => { const languageCountList = []; // 第一层遍历所有国家 for (const country of arr) { // 第二层遍历当前国家的所有语言 for (const lang of country.languages) { // 查找当前语言是否已经在统计列表里 const existRecord = languageCountList.find(item => item.country === lang); if (existRecord) { // 已存在则计数+1 existRecord.count += 1; } else { // 不存在则新增统计记录,初始计数为1 languageCountList.push({ country: lang, count: 1 }) } } } // 按计数从高到低降序排序 languageCountList.sort((a, b) => b.count - a.count); // 截取前n条结果返回 return languageCountList.slice(0, n); };
逻辑说明
- 双层遍历逻辑和最初的思路完全一致:外层遍历所有国家,内层遍历每个国家的语言列表
- 每拿到一门语言,先检查统计列表里有没有对应记录,有就累加计数,没有就新增初始记录,解决重复插入的问题
- 所有语言统计完成后,按计数字段降序排序,保证频次越高的语言排在越前面
- 最后用
slice(0, n)截取排序后数组的前n项,就是需要的结果
测试说明
贴出的示例只包含8个国家,跑出来的统计结果会和写的预期值有差异——预期里的91、45等计数值是基于完整的200+国家全量数据集统计得到的,用8条测试数据调用,返回结果如下:
console.log(mostSpokenLanguages(countries, 3)) /* [ { country: 'English', count: 2 }, { country: 'Pashto', count: 1 }, { country: 'Uzbek', count: 1 } ] */
等熟悉JS基础后,可以尝试用Map或者普通对象做计数存储,查询效率比数组的find方法更高,入门阶段先把双层循环的统计逻辑理清楚即可。
内容的提问来源于stack exchange,提问作者Fagbenja Enoch
相关产品推荐
相关产品推荐

