《数组去重方法总结》


2020-05-23 上次更新时间:8/4/2020, 8:24:44 PM 0 javascript

以下例子皆以这个数组为前提

var arr = [
  1, 1, 15, 15,
  'true', 'false',true,
  false, 'false', true, 0, 
  undefined,  null, null, 
  NaN, 'NaN', NaN, 'NaN', false, undefined,
  0, 'a', 'a', 'true', 
  {'name': 'jack', 'age': 18},
  {'age': 18, 'name': 'jack'},
  {'name': 'lucy', 'age': 20},
  {'name': 'lucy', 'age': 22}
];
1
2
3
4
5
6
7
8
9
10
11
12

# 1. Set

缺点:对象无法去重


function unique (arr) {
  return Array.from(new Set(arr))
}
console.log(unique(arr)) // length:16

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7

或者

[...new Set(arr)] // 结果跟上面一致
1

# 2. Map

缺点:对象无法去重

function unique(arr) {
  let map = new Map();
  let array = new Array();  // 数组用于返回结果
  for (let i = 0; i < arr.length; i++) {
    if(map.has(arr[i])) {  // 如果有该key值
      map.set(arr[i], true); 
    } else { 
      map.set(arr[i], false);   // 如果没有该key值
      array .push(arr[i]);
    }
  } 
  return array ;
}

console.log(unique(arr)) // length: 16

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3. for + splice

缺点:对象无法去重,NaN无法去重

function unique(arr){            
  for(var i = 0; i < arr.length; i++){
      for(var j = i + 1; j < arr.length; j++){
          if(arr[i] === arr[j]){
              arr.splice(j,1);
              j--;
          }
      }
  }
  return arr;
}

console.log(unique(arr)) // length: 17

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN",NaN, "a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4. for + indexOf

缺点:对象无法去重,NaN无法去重

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log('type error!')
    return
  }
  var array = [];
  for (var i = 0; i < arr.length; i++) {
      if (array .indexOf(arr[i]) === -1) {
          array .push(arr[i])
      }
  }
  return array;
}

console.log(unique(arr)) // length: 17

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN",NaN, "a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5. for + includes

缺点:对象无法去重

function unique(arr) {
  if (!Array.isArray(arr)) {
      console.log('type error!')
      return
  }
  var array =[];
  for(var i = 0; i < arr.length; i++) {
    if( !array.includes( arr[i]) ) {
        array.push(arr[i]);
    }
  }
  return array
}

console.log(unique(arr)) // length: 16

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6. for + sort

缺点:对数字/字母排序有效,否则需要传入特定条件进行排序

function unique(arr) {
  if (!Array.isArray(arr)) {
      console.log('type error!')
      return;
  }
  // todo 应该传入条件排序
  arr = arr.sort()
  var arrry= [arr[0]];
  for (var i = 1; i < arr.length; i++) {
      if (arr[i] !== arr[i-1]) {
          arrry.push(arr[i]);
      }
  }
  return arrry;
}

console.log(unique(arr)) // length: 21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 7. filter + hasOwnProperty

缺点:将object类型都去掉了,仅剩一个

function unique(arr) {
    var obj = {};
    return arr.filter(function(item, index, arr){
        console.log('typeof item + item', typeof item + item,'>>>>', obj.hasOwnProperty(typeof item + item))
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
}
console.log(unique(arr)) // length: 13
1
2
3
4
5
6
7
8

# 8. filter + indexOf

缺点:对象无法去重,不能识别 NaN 和 ”NaN“

function unique(arr) {
  return arr.filter(function(item, index, arr) {
    //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
    return arr.indexOf(item, 0) === index;
  });
}
console.log(unique(arr)) // length: 15

// [1,15,"true","false",true,false,0,undefined,null,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]
1
2
3
4
5
6
7
8
9

# 9. reduce + includes

缺点:对象无法去重

function unique(arr){
  return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}

console.log(unique(arr)); // length: 16

// [1,15,"true","false",true,false,0,undefined,null,NaN,"NaN","a",{"name":"jack","age":18},{"age":18,"name":"jack"},{"name":"lucy","age":20},{"name":"lucy","age":22}]

1
2
3
4
5
6
7
8

# 10. lodash 工具库

结果:完美去重

Lodash: 一个一致性、模块化、高性能的 JavaScript 实用工具库

var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.async = true;
oScript.src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js";
document.body.append(oScript)

_.uniqWith(arr, _.isEqual); // length: 15
1
2
3
4
5
6
7

# 11. 对比

方法 优点 缺点
Set 代码量少 对象无法去重
Map 对象无法去重
for + splice 对象无法去重,NaN无法去重
for + indexOf 对象无法去重,NaN无法去重
for + includes 对象无法去重
for + sort 对数字/字母类较有效 需传入特定条件进行排序
filter + hasOwnProperty 将object类型都去掉了,仅剩一个
filter + indexOf 对象无法去重,不能识别 NaN 和 ”NaN“
reduce + includes 对象无法去重
lodash.js 工具库,使用方便,完美去重

总结

以上的方法可以自由组合,除了对象的去重需要特殊处理外,其他的基本都适用。如果数组中掺杂了对象,那么我们只需要判断 对象类型,对对象做特殊的去重处理即可。

# 数组对象去重

以下例子皆以这个数组为前提:

var arr = [
  {'id': 1, 'name': 'jack', 'age': 18},
  {'id': 1, 'age': 18, 'name': 'jack'},
  {'id': 2, 'name': 'lucy', 'age': 20},
  {'id': 3, 'name': 'lucy', 'age': 22},
  {'id': 3, 'name': 'lucy', 'age': 22},
  {'id': 4, 'name': 'lucy', 'age': 22}
]
1
2
3
4
5
6
7
8

# 1. reduce

function unique(arr){
  let obj = {}

  return arr.reduce((prev,cur) => {
    obj[cur.id] ? "" : obj[cur.id] = true && prev.push(cur);
    return prev
  },[]); // 设置 prev 默认类型为数组,并且初始值为空的数组
}

console.log(unique(arr));
1
2
3
4
5
6
7
8
9
10

# 2. Map

function unique(arr){
    let map = new Map();
    for (let item of arr) {
        if (!map.has(item.id)) {
            map.set(item.id, item);
        }
    }
    return [...map.values()];
}
console.log(unique(arr));
1
2
3
4
5
6
7
8
9
10

# 3. Map + Object.values()

function unique(arr){
  let obj = {}
  arr.map(item => {
    obj[item.id] = item
  })
  console.log(obj)
  return Object.values(obj)
}

console.log(unique(arr));
1
2
3
4
5
6
7
8
9
10

# 4. 双重循环

var temp = []
function unique(arr){
  arr.forEach(function(a) {
      var check = temp.every(function(b) {
          return a.id !== b.id;
      })
      check ? temp.push(a) : ''
  })
  return temp;
}

console.log(unique(arr));
1
2
3
4
5
6
7
8
9
10
11
12

# 5. 冒泡排序法

function unique(arr){
  for (var i = 0; i < arr.length - 1; i++) {
      for (var j = i + 1; j < arr.length; j++) {
          if (arr[i].id == arr[j].id) {
              arr.splice(j, 1);
              j--;
          }
      }
  }
  return arr;
}

console.log(unique(arr));
1
2
3
4
5
6
7
8
9
10
11
12
13
上次更新时间: 8/4/2020, 8:24:44 PM