本章要将的东西分前后两个:两数全等数组去重

但其实就是一个东西,判断两复杂对象是否全等

引导

在这之前可能大部分人认为两数相等,== 就行了呀,不行我就 ===,这总可以了吧

虽说 === 是要满足数据类型一致的前提下,满足数据相等。可以满足基本需求

但只对基本类型可行,若是遇到引用类型,即Object对象或Array数组时呢

1
2
3
4
5
6
7
8
9
10
11
console.log([] === [])

let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: 1,
b: 2
}
console.log(obj1 == obj2)

抱歉,管你一不一样,都返回false

即这种 === 对引用类型是无效的


到这可能会有人想把引用类型转化为字符串再去判断不就可以了吗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Array
let arr1 = [1, 2, 3]
let arr2 = [1, 2, 3]

console.log(arr1.toString() == arr2.toString())

// Object
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
a: 1,
b: 2
}
console.log(JSON.stringify(obj1) == JSON.stringify(obj2))

但是,如果数组或对象的值的只是顺序不同呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
// Array
let arr1 = [1, 2, 3]
let arr2 = [3, 1, 2]

// Object
let obj1 = {
a: 1,
b: 2
}
let obj2 = {
b: 1,
a: 2
}

到这可能会有人想把数组或对象先排序之后再转化为字符串,再来判断相等

1
2
3
4
5
6
7
8
9
10
11
12
13
// Array
console.log(arr1.sort().toString() == arr2.sort().toString())

// Object
// 这里只列出排序方法吧
function objSort (obj) {
let sdic = Object.keys(obj).sort()
let newObj = {}
for(ki in sdic){
newObj[sdic[ki]] = obj[sdic[ki]]
}
return newObj
}

通过排序之后,两数组或对象的顺序是一样的,转化为字符串,再判断


但是,如果该数组或对象的值的类型不一致呢?

1
2
3
// Array
let arr1 = [1, '3', '2']
let arr2 = [1, 2, 3]

是不是觉得上面的方法不可用了呢


再但是,如果该数组或对象的值也是一个引用类型呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let arr = [
[1, 2, 2],
[2, 1, 1],
[2, 1, 3]
]

let obj ={
a: {
b: 1,
a: 1
},
b: {
a: 1,
b: '1',
}
}

你猜猜看 [1, 2, 2][2, 1, 1] 谁前谁后?

a: { b: 1, a: 1}b: { a: 1, b: ‘1’} 谁前谁后?

有兴趣你可以自己排序输出看一看,验证自己的猜想


在进一步看,如果数组或对象的值复杂多变,对象嵌数组,数组再嵌对象….

两数相等

所以我这要讲的是这样的两数相等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
foo1 = {
a: 1,
d: [{ b: '3', a: 1}, [2, 1]],
c: false,
f: {
a: '1',
e: [2, 1],
c: {
d: 1,
f: '1'
}
},
e: ['2', 1]
}

foo2 = {
a: '1',
c: false,
d: [[1, 2], { a: 1, b: '3'}],
f: {
e: ['2', 1],
a: '1',
c: {
d: '1',
f: 1
}
},
e: [1, '2']
}

思路分四层:

  • 存在其中有一个数不是对象,走 ===
  • 一数组,另一非数组,直接false
  • 两数均为数组,走数组逻辑(较麻烦)
  • 两都为非数组对象,走对象逻辑

完整判断两数相等函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 判断两对象是否全等
function isEqual (obj1, obj2) {

// 存在非对象
if (!(obj1 instanceof Object) || !(obj2 instanceof Object)) {
return obj1 === obj2

// 如果不用全等===,可以选择用下面的
// if (typeof obj1 != typeof obj2) {
// return false
// } else {
// return obj1 == obj2
// }
}

// 一数组,另一非数组
if (obj1 instanceof Array != obj2 instanceof Array) {
return false

// 两均为数组
} else if (obj1 instanceof Array && obj2 instanceof Array) {
if (obj1.length != obj2.length) {
return false
} else {
// 坑 -定义新数组,标记某个已经匹配到位置为1,一旦匹配不到false
let arr = new Array(obj2.length).join(0).split(' ')
for(let item1 of obj1){
let i;
for(i = 0; i < obj2.length ; i++){
if (arr[i] != 1&&isEqual(item1,obj2[i])) { // 起初想匹配到一个删除一个,但实际用途中可能还需要原对象,尽量不去修改原数组
arr[i] = 1
break;
}
}
if (i>=obj2.length) {
return false
}
}
return true
}

// 两都为非数组对象
} else {
if (Object.keys(obj1).length != Object.keys(obj2).length) {
return false
}
// 按道理,对象不能存在多个相同的key
for(let attr in obj1){
if (!obj2.hasOwnProperty(attr)) {
return false
}
if (!isEqual(obj1[attr], obj2[attr])) {
return false
}
}
return true

}
}

通用方法,类型复杂多变,要考虑所有情况,

数组去重

对于普通的的数组,去重方法有很多种,直接遍历,利用indexOf索引,利用对象的属性等等。

以及ES6的Set

  • Array.from将Set结构转换成数组
1
2
3
4
function dedupe(array){
return Array.from(new Set(array))
}
dedupe([1,1,2,3])
  • 拓展运算符(…)内部使用for…of循环
1
2
3
let arr = [1,2,3,3]
let newArr = [...new Set(arr)]
console.log(newArr)

但通过上面的分析,也应当知道,此处要讲的也不是简单的数组,数组的每一项也是复杂多变的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let arr2 = [
2,
{
b: 2,
a: 1,
c: [3]
},{
a: 1,
b: 2,
c: [3]
},
'2',
['1', 2, 1],
[2, '1', 1]
]

这样的数组,用上面的去重方法,都行不通

但我们已经有了一个判断两数相等的函数了不是吗

数组去重函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function removeDuplication (array) {
let newArr = []
for (let item of array) {
let i
for (i=0; i<newArr.length;i++) {
if(isEqual(item, newArr[i])) {
break;
}
}
if (i>=newArr.length) {
newArr.push(item)
}
}
return newArr
}

利用isEqual去检索是否已经包含该数值。

总结

本次分享了两个函数,两数相等isEqual函数,数组去重removeDuplication函数

基本通用

如若有误,可diss我, 欢迎指正

如若你有更好的方法,Share ~