从JavaScript数组中移除重复值
技术背景
在JavaScript开发中,经常会遇到需要从数组中移除重复值的场景。例如,处理用户输入的数据、合并多个数组后去除重复元素等。不同的去重方法在性能、适用场景和代码简洁性上有所差异。
实现步骤
1. 使用Set和扩展运算符
Set是ES6引入的新的数据结构,它类似于数组,但成员的值都是唯一的。结合扩展运算符...
可以很方便地将Set转换为数组。
1
| const uniq = [...new Set(array)];
|
2. 使用filter和indexOf方法
通过filter
方法过滤出数组中首次出现的元素。
1 2 3
| const uniqueArray = a.filter(function(item, pos) { return a.indexOf(item) == pos; });
|
或者使用ES6箭头函数的简写形式:
1
| const uniqueArray = a.filter((item, pos) => a.indexOf(item) === pos);
|
3. 使用哈希表
利用对象作为哈希表来记录元素是否已经出现过。
1 2 3 4 5 6
| function uniq(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); }
|
4. 通用解决方案
结合哈希查找和线性搜索,对基本类型使用哈希查找,对对象使用线性搜索。
1 2 3 4 5 6 7 8 9 10 11
| function uniq(a) { var prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];
return a.filter(function(item) { var type = typeof item; if(type in prims) return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); else return objs.indexOf(item) >= 0 ? false : objs.push(item); }); }
|
5. 先排序再去重
先对数组进行排序,然后过滤掉与前一个元素相同的元素。
1 2 3 4 5
| function uniq(a) { return a.sort().filter(function(item, pos, ary) { return !pos || item != ary[pos - 1]; }); }
|
6. 根据特定条件去重
通过传递一个回调函数来指定去重的条件。
1 2 3 4 5 6 7
| function uniqBy(a, key) { var seen = {}; return a.filter(function(item) { var k = key(item); return seen.hasOwnProperty(k) ? false : (seen[k] = true); }) }
|
核心代码
以下是几种常见方法的核心代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const array = [1, 2, 2, 3, 4, 4, 5]; const uniq = [...new Set(array)]; console.log(uniq);
const uniqueArray = array.filter((item, pos) => array.indexOf(item) === pos); console.log(uniqueArray);
function uniqWithHash(a) { var seen = {}; return a.filter(function(item) { return seen.hasOwnProperty(item) ? false : (seen[item] = true); }); } console.log(uniqWithHash(array));
|
最佳实践
- 对于基本类型数组:优先使用
Set
和扩展运算符的方法,代码简洁且性能较好。
1 2 3
| const numbers = [1, 2, 2, 3, 3, 4]; const uniqueNumbers = [...new Set(numbers)]; console.log(uniqueNumbers);
|
- 对于需要自定义去重条件的数组:使用
uniqBy
函数,通过传递合适的回调函数来实现。
1 2 3 4 5 6 7
| const objects = [ { id: 1, name: 'John' }, { id: 2, name: 'Jane' }, { id: 1, name: 'John' } ]; const uniqueObjects = uniqBy(objects, obj => obj.id); console.log(uniqueObjects);
|
常见问题
1. 哈希表方法无法区分数字和字符串
由于JavaScript中哈希键只能是字符串或符号,哈希表方法无法区分数字和“数字字符串”。例如,uniq([1, "1"])
会返回[1]
。
2. 排序去重方法对对象无效
排序去重方法依赖于元素的比较,对于对象来说,由于对象的比较规则不同,该方法无法正确去重。
3. 性能问题
使用filter
和indexOf
方法的时间复杂度为$O(n^2)$,对于大数组来说性能较差。可以使用哈希表或Set
方法将时间复杂度降低到$O(n)$。