JavaScript数组去重并记录重复项索引的核心是识别重复元素及其所有位置,推荐用Map存储各值对应的所有索引;可进一步筛选重复项、分离首次与后续索引,或封装返回去重数组与重复映射对象,并注意类型敏感性。

JavaScript 数组去重时想同时记录重复项的索引位置,关键不是只保留唯一值,而是**识别哪些元素重复、在哪些位置出现过**。下面提供几种实用方法,按不同需求场景组织。
用 Map 记录每个值对应的所有索引
这是最清晰、推荐的方案:遍历一次数组,把每个值作为 key,其所有出现的索引组成数组作为 value 存入 Map。
const arr = ['a', 'b', 'a', 'c', 'b', 'a'];
const indexMap = new Map();
arr.forEach((item, index) => {
if (!indexMap.has(item)) {
indexMap.set(item, []);
}
indexMap.get(item).push(index);
});
// 结果:Map(3) { 'a' => [0, 2, 5], 'b' => [1, 4], 'c' => [3] }
// 只取重复项(出现次数 ≥ 2):
const duplicates = Array.from(indexMap.entries())
.filter(([, indexes]) => indexes.length > 1)
.reduce((obj, [val, indexes]) => {
obj[val] = indexes;
return obj;
}, {});
// { a: [0, 2, 5], b: [1, 4] }
获取所有重复元素的首次和后续索引(适合标记/高亮)
如果目标是知道“谁是重复的”,以及“哪些索引该被处理(比如删除、标红)”,可以分离出唯一值索引和重复索引:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 Set 跟踪已见值
- 用数组收集重复项的索引(跳过第一次)
const arr = [1, 2, 3, 2, 4, 3, 3];
const seen = new Set();
const duplicateIndexes = [];
arr.forEach((item, index) => {
if (seen.has(item)) {
duplicateIndexes.push(index);
} else {
seen.add(item);
}
});
// duplicateIndexes → [3, 5, 6]
// 对应的重复值:arr[3]=2, arr[5]=3, arr[6]=3
返回去重后数组 + 完整重复映射(兼顾结果与溯源)
既想要干净的去重数组,又不丢失原始索引信息,可封装为对象返回:
立即学习“Java免费学习笔记(深入)”;
function dedupeWithIndex(arr) {
const seen = new Set();
const uniqueArr = [];
const duplicateMap = new Map();
arr.forEach((item, index) => {
if (seen.has(item)) {
if (!duplicateMap.has(item)) duplicateMap.set(item, [index]);
else duplicateMap.get(item).push(index);
} else {
seen.add(item);
uniqueArr.push(item);
}
});
return {
unique: uniqueArr,
duplicates: Object.fromEntries(duplicateMap)
};
}
// 使用示例
const result = dedupeWithIndex(['x', 'y', 'x', 'z', 'y']);
// {
// unique: ['x', 'y', 'z'],
// duplicates: { x: [2], y: [4] }
// }
注意数字与字符串的隐式转换问题
若数组含混合类型(如 1 和 '1'),默认比较会认为它们相等(1 == '1')。需明确是否要严格区分:
- 用
===或Object.is()判断时,1 和 '1' 是不同键 - Map 默认用
Object.is(),所以天然支持类型敏感 - 若需忽略类型(统一转字符串),提前做
String(item)

















