JavaScript如何统计对象数组中属性值的出现次数
问题说明
你给出的示例数组存在语法笔误:第一个国家对象缺少闭合的},修正后的基础测试数据如下:
const countriesSample = [{ name: "Yemen", capital: "Sana'a", languages: ["Arabic"], }, { name: "Zambia", capital: "Lusaka", languages: ["English"], }, { name: "Zimbabwe", capital: "Harare", languages: ["Shona", "English", "Northern Ndebele"], }, ];
需求是统计所有国家languages数组中每个语言的出现次数,最终输出{language: 语言名, count: 出现次数}格式的数组,且不使用显式for循环实现。
你之前写的循环逻辑存在几个明显错误:
- 内层循环遍历
countries[i].length没有意义,countries[i]是单个国家对象,不存在length属性,应该遍历的是countries[i].languages - 计数逻辑错误,你在累加数组长度,没有按单个语言维度分类统计,只能得到所有语言的总数量,得不到每个语言的单独计数
- 索引使用混乱,内层循环用
j索引取countries[j]属于逻辑错位
实现方案
直接用数组内置方法组合即可实现,不需要写显式for循环。
基础实现(和示例输出顺序一致)
核心逻辑分三步:先把所有嵌套的语言数组拍平成一维列表,再统计每个语言的出现频次,最后转换成要求的结构并按频次降序排序:
// 1. 拍平+统计频次 const langCount = countriesSample .flatMap(country => country.languages) .reduce((res, lang) => { res[lang] = (res[lang] || 0) + 1; return res; }, {}); // 2. 格式转换+排序 const result = Object.entries(langCount) .map(([language, count]) => ({language, count})) .sort((a, b) => b.count - a.count);
运行后得到的结果和你给出的期望输出完全一致。
逻辑说明
flatMap会遍历每个国家项,取出languages数组后自动把所有数组合并成一维的语言列表,比先map再flat的写法性能更好reduce用一个普通对象做哈希表,遍历一维语言列表时累计每个语言的出现次数Object.entries把存统计结果的对象转成[语言名, 计数]格式的二维数组,再通过map转成要求的对象结构- 最后加的
sort是为了让出现次数高的语言排在前面,和你给出的示例顺序匹配
更稳妥的实现(避免键名冲突)
如果担心语言名和Object原型上的属性重名导致统计异常,可以用Map作为统计容器:
const langCountMap = countriesSample .flatMap(country => country.languages) .reduce((map, lang) => { map.set(lang, (map.get(lang) || 0) + 1); return map; }, new Map()); const result = Array.from(langCountMap, ([language, count]) => ({language, count})) .sort((a, b) => b.count - a.count);
内容的提问来源于stack exchange,提问作者Clevermaniac
相关产品推荐
相关产品推荐

