JavaScript:用.filter()获取去重后的重复字母及替代方案
问题
我想用.filter()从字符串里提取重复的字母组成新数组,但希望每个重复字母只出现一次,不管它重复多少次。我写的代码如下:
const fullName = "Muhammad Ali"; const fullNameLowercase = fullName.toLowerCase(); const splitName = fullNameLowercase.split(""); let repeats = splitName.filter((letter, index) => {return splitName.indexOf(letter) !== index}); console.log(repeats); // 输出 [ 'm', 'm', 'a', 'a' ]
现在输出的数组里重复字母出现了多次,怎么改才能让每个重复字母只留一次?另外有没有不用.filter()的更高效办法?
用.filter()的改进实现
你原来的代码会把每一次重复出现的字符都保留下来,要实现去重,可以在过滤逻辑里加个判断:只保留第一次被检测到重复的那个字符,或者用一个集合记录已经加入结果的字符。
方案1:利用lastIndexOf判断
const fullName = "Muhammad Ali"; const fullNameLowercase = fullName.toLowerCase(); const splitName = fullNameLowercase.split(""); let repeats = splitName.filter((letter, index) => { // 当前字符不是第一次出现,且是最后一次出现的位置——这样就能只保留最后一个重复项 return splitName.indexOf(letter) !== index && splitName.lastIndexOf(letter) === index; }); console.log(repeats); // 输出 [ 'm', 'a' ]
方案2:用Set记录已添加的字符
const fullName = "Muhammad Ali"; const fullNameLowercase = fullName.toLowerCase(); const splitName = fullNameLowercase.split(""); const seen = new Set(); const repeats = splitName.filter((letter) => { // 先判断这个字符是否是重复的(出现次数大于1) const isDuplicate = splitName.indexOf(letter) !== splitName.lastIndexOf(letter); // 如果是重复字符且没被记录过,就加入结果并标记为已见过 if (isDuplicate && !seen.has(letter)) { seen.add(letter); return true; } return false; }); console.log(repeats); // 输出 [ 'm', 'a' ]
更高效的非.filter()实现
原方法里多次调用indexOf和lastIndexOf,每次都是遍历整个数组,时间复杂度是O(n²),处理长字符串时效率很低。可以用一次遍历统计字符出现次数,再筛选出次数大于1的字符,时间复杂度能降到O(n)。
用普通对象统计次数
const fullName = "Muhammad Ali"; const fullNameLowercase = fullName.toLowerCase(); const countMap = {}; // 第一次遍历,统计每个字符出现的次数 for (const letter of fullNameLowercase) { countMap[letter] = (countMap[letter] || 0) + 1; } // 提取出现次数大于1的字符 const repeats = Object.keys(countMap).filter(letter => countMap[letter] > 1); console.log(repeats); // 输出 [ 'm', 'a' ]
用Map统计次数
const fullName = "Muhammad Ali"; const fullNameLowercase = fullName.toLowerCase(); const countMap = new Map(); // 统计字符出现次数 for (const letter of fullNameLowercase) { countMap.set(letter, (countMap.get(letter) || 0) + 1); } // 筛选重复字符 const repeats = []; for (const [letter, count] of countMap) { if (count > 1) { repeats.push(letter); } } console.log(repeats); // 输出 [ 'm', 'a' ]
内容的提问来源于stack exchange,提问作者claramarsango
相关产品推荐
相关产品推荐

