原始类型去重
我们在接触编程的时候,或多或少都会接触过一些去除数组中重复项这种问题,每个语言有每个语言自己的去重方式,接下来我们来看看js中的数组去重可以用什么方式实现。
双层 for 循环
思路:
- 我们需要先创建一个数组
newArr
用来存放结果- 对原数组进行遍历,将每一个元素与
newArr
中的每一项进行对比。- 如果发现已经存在就直接
break
然后用arr
的下一项与newArr
中的每一项对比,如果遍历完之后没有相同的元素就将该项插入newArr
中
js
const arr = [1, 2, 3, 4, 2, 1]
function unique(arr) {
let newArr = [] // 用来存放结果
for (let i = 0; i < arr.length; i++) {
for (var j = 0; j < newArr.length; j++) {
// 判断新数组是否已经具有该数值
if (arr[i] === newArr[j]) break
}
if (j === newArr.length) newArr.push(arr[i])
}
return newArr
}
console.log(unique(arr));
for + includes / indexOf
使用这种方法我们得先来了解一下数组中的 includes()
和 indexxOf()
这两个方法。
-
includes() 方法用来判断一个数组是否包含一个指定的值,如果是 则返回 true ,否 则返回false。
-
indexOf() 方法可返回数组中某个指定的元素位置。 该方法将从头到尾地检索数组,看它是否含有对应的元素。开始检索的位置在数组 start 处或数组的开头(没有指定 start 参数时)。如果找到一个 item,则返回 item 的第一次出现的位置。 开始位置的索引为 0。 如果在数组中没找到指定元素则返回 -1。
思路:
- 先创建一个数组
newArr
用来存放结果- 对原数组中的每一项进行遍历,将每一个元素使用
includes / indexOf
方法与newArr
中的数据进行对比- 如果存在就跳过该项让原数组下一项与
newArr
中的每一项进行对比,如果不存在则将该项放入newArr
数组中
js
const arr = [1, 2, 3, 4, 2, 1]
function unique(arr) {
let newArr = []
for (let i = 0; i < arr.length; i++) {
// if (newArr.indexOf(arr[i]) === -1) newArr.push(arr[i])//时间复杂度O(n^2)因为indexOf会再循环一遍
if (!newArr.includes(arr[i])) newArr.push(arr[i])//存在的话返回true,否则返回false
}
return newArr
}
sort + filter
看了上面的两种方法之后,大家可能会觉得上面这两种代码写的有点太长了,我们可不可以再精简一点,接下来我们直接用三行核心代码来解决这个问题。
思路:
- 先将数组进行排序
- 对排序后的数组进行遍历,如果前一项和后一项相同就过滤该项,否则就将该项放入新数组中
js
const arr = [1, 2, 3, 4, 2, 1]
function unique(arr) {
return arr.sort((a, b) => a - b).filter((item, index, array) => {
return !index || item !== array[index - 1]
})
}
console.log(unique(arr));
tips:sort中一定要放回调函数指定排序顺序,否则可能会出错
filter + {}
哈希表相信大家都听过,简单来讲呢我们可以将它先看成是一个对象,而对象中的key是唯一的,我们现在的这个方法就是根据这个特性来实现的。
思路
- 先创建一个哈希表
- 使用
filter()
对数组中的元素进行过滤- 如果存在于哈希表中就跳过,否则将其放入新数组中
js
const arr = [1, 2, 3, 1, 2]
function unique(arr) {
let obj = {}
return arr.filter((item) => {
return obj[item] ? false : obj[item] = true
})// 时间复杂度O(n)
}
console.log(unique(arr));
Set
Set
这种数据结构是ES6中新增的语法,这个数据结构有一个特点就是内部的元素是唯一的,根据这一特点我们只需要将数组放入Set中就会帮我们自动进行去重。
js
const arr = [1, 2, 3, 1, 2]
function unique(arr) {
return [...new Set(arr)]//时间复杂度O(2n)首先先遍历数组放入set,然后再遍历set放入[]
}
console.log(unique(arr));
引用类型去重
在js中的类型我们通常将其分为引用类型和原始类型,而他们之中最主要的区别就是引用类型是存放在堆中的,我们平常对引用类型的赋值通常都是直接给一个地址,取值的时候直接从对应的地址中取值即可。
当我们在数组中存放的都是引用类型的时候,就不能简单的根据数组的下标来进行内容的判断了,因为引用类型存放在数组中的话存放的是地址,但是我们要求的是将地址内部内容一样的给去除,接下来我们来实现一下。
思路:我们需要使用双层for循环的思路来对原数组进行去重,核心就是如何比较两个对象中内容是否相同。
js
let arr = [
{ name: '张三', age: 18 },
{ name: '李四', age: 20 },
{ name: '王五', age: 22 },
{ name: '赵六', age: 24 },
{ name: '钱七', age: 26 },
{ name: '孙八', age: 28 },
{ name: '周九', age: 30 },
{ name: '张三', age: 18 }
]
function unique(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
let flag = false
for (let j = 0; j < res.length; j++) {
if (equals(arr[i], res[j])) {
flag = true
break
}
}
if (!flag) res.push(arr[i])
}
return res
}
上述代码是一个大致的流程,相信大家肯定都看得懂,就是将数组中的每一项遍历并且与res
这个存放结果的数组中的元素进行比较,如果存在相同的则跳过,否则就插入。而代码的核心就是equals(arr[i], res[j])
,接下来我们来为大家讲解一下这个函数中的逻辑。
思路:
- 首先我们的
arr
中存放的可能不止引用类型,还有原始类型,我们需要先对传入的两项进行判断,如果是原始类型则直接比较,否则就进行引用类型的比较- 如果是引用类型,我们先判断两个引用类型中
key
的数量是不是一样,如果不是,那就一定不同返回false
。- 如果传入的两个参数的
key
数量是一致的,那么我们就用for in
对两个引用类型进行遍历- 在遍历两个引用类型的过程中,我们需要判断key是否在另一个对象中存在,如果不存在就返回
false
,否则,我们接着对该key
对应的value
进行比较- 在对两个引用类型的value进行比较的过程中有可能里面还是引用类型,这时候我们就可以再次调用本身
equals()
来对value进行判断,这个过程就是我们所讲的递归
。
接下来给大家展现完整代码:
js
let arr = [
{ name: '张三', age: 18 },
{ name: '李四', age: 20 },
{ name: '王五', age: 22 },
{ name: '赵六', age: 24 },
{ name: '钱七', age: 26 },
{ name: '孙八', age: 28 },
{ name: '周九', age: 30 },
{ name: '张三', age: 18 }
]
function unique(arr) {
let res = []
for (let i = 0; i < arr.length; i++) {
let flag = false
for (let j = 0; j < res.length; j++) {
if (equals(arr[i], res[j])) {
flag = true
break
}
}
if (!flag) res.push(arr[i])
}
return res
}
function equals(v1, v2) {
// 判断是不是引用类型
if ((typeof v1 === 'object' && v1 !== null) && (typeof v2 === 'object' && v2 !== null)) {
// 判断key数量是否相等
if (Object.keys(v1).length !== Object.keys(v2).length) return false
for (let key in v1) {
// 判断两者是否都有相同的key
if (key in v2) {
// 递归比较两者的value
if (!equals(v1[key], v2[key])) return false
} else {
return false
}
}
return true
} else {
return v1 === v2
}
}
console.log(unique(arr))