💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 双层循环 在这个方法中,我们使用循环嵌套,最外层循环 array,里面循环 res,如果 array[i] 的值跟 res[j] 的值相等,就跳出循环,如果都不等于,说明元素是唯一的,这时候 j 的值就会等于 res 的长度,根据这个特点进行判断,将值添加进 res ~~~ function unique(array) { // res用来存储结果 var res = []; for (var i = 0, arrayLen = array.length; i < arrayLen; i++) { for (var j = 0, resLen = res.length; j < resLen; j++ ) { if (array[i] === res[j]) { break; } } // 如果array[i]是唯一的,那么执行完循环,j等于resLen if (j === resLen) { res.push(array[i]) } } return res; } ~~~ <br> <br> # indexOf 外层遍历目标数组,循环内用indexOf判断当前项是否在 res 数组中 ~~~ function unique(array) { var res = []; for (var i = 0, len = array.length; i < len; i++) { var current = array[i]; if (res.indexOf(current) === -1) { res.push(current) } } return res; } ~~~ <br> <br> # 排序后去重 试想我们先将要去重的数组使用 sort 方法排序后,相同的值就会被排在一起,然后我们就可以只判断当前元素与上一个元素是否相同,相同就说明重复,不相同就添加进 res ~~~ function unique(array) { var res = []; var sortedArray = array.concat().sort(); var seen; for (var i = 0, len = sortedArray.length; i < len; i++) { // 如果是第一个元素或者相邻的元素不相同 if (!i || seen !== sortedArray[i]) { res.push(sortedArray[i]) } seen = sortedArray[i]; } return res; } ~~~ <br> <br> # filter + indexOf ~~~ function unique(array) { var res = array.filter(function(item, index, array){ return array.indexOf(item) === index; }) return res; } ~~~ <br> <br> # filter + sort ~~~ function unique(array) { return array.concat().sort().filter(function(item, index, array){ return !index || item !== array[index - 1] }) } ~~~ <br> <br> # Set ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值 ~~~ function unique(array) { return [...new Set(array)]; } ~~~ <br> <br> # Map ~~~ function unique (arr) { const seen = new Map() return arr.filter((a) => !seen.has(a) && seen.set(a, 1)) } ~~~ <br> <br> # Object 键值对 将对象序列化可以用来判断对象值是否相等 ~~~ var array = [{value: 1}, {value: 1}, {value: 2}]; function unique(array) { var obj = {}; return array.filter(function(item, index, array){ console.log(typeof item + JSON.stringify(item)) return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true) }) } console.log(unique(array)); // [{value: 1}, {value: 2}] ~~~ <br> <br> # 自定义处理函数 当需要对数组项做特殊处理时,需要自定义函数。如:字母的大小写视为一致,比如'a'和'A',保留一个 ~~~ /** * * @param {Array} array 表示要去重的数组,必填 * @param {Boolean} isSorted 表示函数传入的数组是否已排过序,如果为 true,将会采用更快的方法进行去重 * @param {Function} iteratee 传入一个函数,可以对每个元素进行重新的计算,然后根据处理的结果进行去重 */ var array = [1, 1, 'a', 'A', 2, 2]; function unique2(array, isSorted, iteratee) { var res = [] var seen = [] for (var i = 0, len = array.length; i < len; i++) { var value = array[i] var computed = iteratee ? iteratee(value, i, array) : value if (isSorted) { if (!i || seen !== computed) { res.push(value) } seen = computed } else if (iteratee) { if (seen.indexOf(computed) === -1) { seen.push(computed) res.push(value) } } else if (res.indexOf(value) === -1) { res.push(value) } } return res } unique(array, false, function(item){ return typeof item == 'string' ? item.toLowerCase() : item }) ~~~ <br> <br> # 特殊类型比较 对于这样一个数组 ~~~js var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN]; ~~~ 以上各种方法去重的结果到底是什么样的呢? | 方法 | 结果 | 说明 | | --- | --- | --- | | for循环 | \[1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN\] | 对象和 NaN 不去重 | | indexOf | \[1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN\] | 对象和 NaN 不去重 | | sort | \[/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined\] | 对象和 NaN 不去重 数字 1 也不去重 | | filter + indexOf | \[1, "1", null, undefined, String, String, /a/, /a/\] | 对象不去重 NaN 会被忽略掉 | | filter + sort | \[/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined\] | 对象和 NaN 不去重 数字 1 不去重 | | 优化后的键值对方法 | \[1, "1", null, undefined, String, /a/, NaN\] | 全部去重 | | Set | \[1, "1", null, undefined, String, String, /a/, /a/, NaN\] | 对象不去重 NaN 去重 | <br> 想了解为什么会出现以上的结果,看两个 demo 便能明白: ~~~js // demo1 var arr = [1, 2, NaN]; arr.indexOf(NaN); // -1 ~~~ indexOf 底层还是使用 === 进行判断,因为 NaN === NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素 ~~~js // demo2 function unique(array) { return Array.from(new Set(array)); } console.log(unique([NaN, NaN])) // [NaN] ~~~ Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。 # 参考资料 [JavaScript专题之数组去重](https://github.com/mqyqingfeng/Blog/issues/27)