JS基础篇:数组去重


数组去重有哪些方法?

  1. 利用 es6 中的 Set 去重,将数组传入到 Set 方法中就可以了
  2. 两层 for 循环+ splice,如果拿每个元素与后面元素进行对比,如果有相同就讲后面重复的元素用 splice 删除掉
  3. indexof 实现去重,创建一个空数组,然后遍历原数组,取出每个值,进行 indexof 判断,如果等于-1 表示不存在,加入到新数组中。
  4. 利用 sort 进行排序,,然后两两相邻比较,如果不相等就加入到新数组中
  5. 利用 includes 判断新数组中是否存在该元素,如果不存在就添加
  6. 利用 filter 如果找的那个元素的索引和遍历的当前索引一直,表示只有一个 ,则添加

纯数组去重

方法一:利用 ES6 Set 去重(ES6 中最常用)

function unique(arr) {
  return Array.from(new Set(arr));
}
var arr1 = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, 0, 'a', {}, {}]
//{}没有去重

如果不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方法会添加去掉重复“{}”的方法。

方法二:利用 for 嵌套 for,然后 splice 去重(ES5 中最常用)

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;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [1, 2, 'true', 'b', 15, false, undefined, NaN, NaN, 'a', {}, {}]
//NaN和{}没有去重,2个null都去掉了

方法三:利用indexOf去重

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;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); //[1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, NaN, 0, 'a', {}, {}]
//NaN,{}没有去重

新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则 push 进数组。

方法四:利用sort()

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log("type error!");
    return;
  }
  arr = arr.sort();
  var array = [arr[0]];
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] !== arr[i - 1]) {
      array.push(arr[i]);
    }
  }
  return array;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); //[0, 1, 15, 2, NaN, NaN, {}, {}, 'a', 'b', false, null, 'true', true, undefined]
//NaN,{}没有去重

利用 sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。

方法五:利用对象的属性不能相同的特点进行去重

function unique(arr) {
  if (!Array.isArray(arr)) {
    console.log("type error!");
    return;
  }
  var array = [];
  var obj = {};
  for (var i = 1; i < arr.length; i++) {
    if (!obj[arr[i]]) {
      array.push(arr[i]);
      obj[arr[i]] = 1;
    } else {
      obj[arr[i]]++;
    }
  }
  return array;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [2, 1, 'true', 'b', 15, false, undefined, null, NaN, 0, 'a', {}]
//2个true都去掉了,NaN,{}去重

方法六:利用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])) {
      //includes 检测数组是否有这个值
      array.push(arr[i]);
    }
  }
  return array;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); //[1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, 0, 'a', {}, {}]
//{}没有去重

方法七:利用hasOwnProperty

function unique(arr) {
  var obj = {};
  return arr.filter((item, index, arr) => {
    return obj.hasOwnProperty(typeof item + item)
      ? false
      : (obj[typeof item + item] = true);
  });
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); //[1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, 0, 'a', {}]
//所有的都去重了

利用 hasOwnProperty 判断是否存在对象属性

扩展:hasOwnProperty()

语法:obj.hasOwnProperty(prop) ,参数 prop 为字符串

  • js 原生方法, object.prototype.hasOwnProperty()
  • 返回值: 返回一个布尔值, 判断该对象是否含有指定属性, 不包含继承来的属性
var obj = new Object();
obj.prop = "wang";

obj.hasOwnProperty("prop"); //true
delete o.prop;
obj.hasOwnProperty("prop"); //false

方法八:利用filter

function unique(arr) {
  var obj = {};
  return arr.filter((item, index, arr) => {
    return arr.indexOf(item, 0) === index;
  });
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [1, 2, 'true', 'b', true, 15, false, undefined, null, 0, 'a', {}, {}]
//2个NaN都去掉了,{}没有去重

方法九:利用递归去重

只适合纯数字数组,不适合字符串数组

function unique(arr) {
  var array = arr;
  var len = array.length;

  array.sort(function (a, b) {
    //排序后更加方便去重
    return a - b;
  });

  function loop(index) {
    if (index >= 1) {
      if (array[index] === array[index - 1]) {
        array.splice(index, 1);
      }
      loop(index - 1); //递归loop,然后数组去重
    }
  }
  loop(len - 1);
  return array;
}
var arr1 = [
  1,
  2,
  1,
  "true",
  "b",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
var arr2 = [1, 2, 1, 4, 5, 2];

console.log(unique(arr1)); // [1, 2, 'true', 'b', 'true', false, null, 0, true, 15, NaN, NaN, 'a', {}, {}, undefined]
console.log(unique(arr2)); //[1, 2, 4, 5]

方法十:利用Map数据结构去重

function unique(arr) {
  let map = new Map();
  let array = new Array(); //数组用于返回结果
  for (var i = 0; i < arr.length; i++) {
    if (map.has(arr[i])) {
      //如果有该key值
      map.set(arr[i], true);
    } else {
      map.set(arr[i], false);
      array.push(arr[i]);
    }
  }
  return array;
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, 0, 'a', {}, {}]
//{}没有去重

创建一个空 Map 数据结构,遍历需要去重的数组,把数组的每一个元素作为 key 存到 Map 中。由于 Map 中不会出现相同的 key 值,所以最终得到的就是去重后的结果。

方法十一:利用reduce+includes

function unique(arr) {
  return arr.reduce(
    (prev, cur) => (prev.includes(cur) ? prev : [...prev, cur]),
    []
  );
}
var arr = [
  1,
  2,
  1,
  "true",
  "b",
  "true",
  true,
  true,
  15,
  15,
  false,
  false,
  undefined,
  undefined,
  null,
  null,
  NaN,
  NaN,
  0,
  0,
  "a",
  "a",
  {},
  {},
];
console.log(unique(arr)); // [1, 2, 'true', 'b', true, 15, false, undefined, null, NaN, 0, 'a', {}, {}]
//{}没有去重

对象数组去重

方法一:对象访问属性

采用对象访问属性的方法,判断属性值是否存在,如果不存在就添加。

var arr = [
  {
    key: "01",
    value: "乐乐",
  },
  {
    key: "02",
    value: "博博",
  },
  {
    key: "03",
    value: "淘淘",
  },
  {
    key: "04",
    value: "哈哈",
  },
  {
    key: "01",
    value: "乐乐",
  },
];

//  方法1:利用对象访问属性的方法,判断对象中是否存在key
var result = [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
  if (!obj[arr[i].key]) {
    result.push(arr[i]);
    obj[arr[i].key] = true;
  }
}
console.log(result); // [{key: "01", value: "乐乐"},{key: "02", value: "博博"},{key: "03", value: "淘淘"},{key: "04", value: "哈哈"}]

方法二:reduce方法

采用数组中的 reduce 方法,遍历数组,也是通过对象访问属性的方法

//  方法2:利用reduce方法遍历数组,reduce第一个参数是遍历需要执行的函数,第二个参数是item的初始值
var obj = {};
arr = arr.reduce(function (item, next) {
  obj[next.key] ? "" : (obj[next.key] = true && item.push(next));
  return item;
}, []);
console.log(arr); // [{key: "01", value: "乐乐"},{key: "02", value: "博博"},{key: "03", value: "淘淘"},{key: "04", value: "哈哈"}]

两个对象数组去重

方法一:​​filter+findIndex方法

方法

const uniqueArray = mergedArray.filter(
  (item, index, self) => index === self.findIndex((t) => t.id === item.id)
);

工作原理
filter 方法会遍历 mergedArray 中的每一个元素。
对于每个元素,使用 findIndex 查找该元素在 mergedArray 中第一次出现的索引。
如果当前元素的索引与第一次出现的索引相同,则该元素是唯一的,会被保留在 uniqueArray 中。

性能
这种方法的时间复杂度是 O(n^2),因为对于每个元素都要调用一次 findIndex,这会导致在数组较大时性能下降。

优势
这种方代码简洁性优先,数据规模较小(如 < 1000 项)或无需频繁调用。

该方法可匹配多个参数进行去重。

示例

const array1 = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];
const array2 = [
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];
const mergedArray = [...array1, ...array2];
const uniqueArray = mergedArray.filter(
  (item, index, self) => index === self.findIndex((t) => t.id === item.id)
);
console.log(uniqueArray);

方法二:​reduce+some方法

方法

const uniqueArray = mergedArray.reduce((acc, item) => {
  if (!acc.some((existingItem) => existingItem.id === item.id)) {
    acc.push(item);
  }
  return acc;
}, []);

工作原理
reduce 方法会遍历 mergedArray 中的每一个元素,并将结果累积到 acc(累加器)中。
对于每个元素,使用 some 方法检查 acc 中是否已经存在具有相同 id 的元素。
如果不存在,则将当前元素添加到 acc 中。

性能
这种方法的时间复杂度也是 O(n^2),因为对于每个元素都要调用一次 some,但在某些情况下,它可能会比 filterfindIndex 方法更高效,尤其是当数组较大且重复元素较少时。

优势
需要显式控制累积过程(如添加额外逻辑),或需与其他 reduce 操作结合使用。

该方法可匹配多个参数进行去重。

示例

const array1 = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];
const array2 = [
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];
const mergedArray = [...array1, ...array2];
const uniqueArray = mergedArray.reduce((acc, item) => {
  if (!acc.some((existingItem) => existingItem.id === item.id)) {
    acc.push(item);
  }
  return acc;
}, []);
console.log(uniqueArray);

方法三:使用 MapSet方法

通过 Map 存储已处理的 id,时间复杂度降为 O(n)
方法

const uniqueArray = [
  ...new Map(mergedArray.map((item) => [item.id, item])).values(),
];

由于把id作为Mapkey,所以该方法不支持匹配多个参数进行去重。

示例

const array1 = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];

const array2 = [
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];

const mergedArray = [...array1, ...array2];

const uniqueArray = Array.from(
  new Map(mergedArray.map((item) => [item.id, item])).values()
);

console.log(uniqueArray);

方法四:使用 lodash 库的 _.uniqBy

如果你在项目中使用了 Lodash 库,可以使用它的 uniqBy 方法来快速去重。

方法

const _ = require("lodash");
const uniqueArray = _.uniqBy(mergedArray, "id");

该方法不支持匹配多个参数进行去重。

示例

const _ = require("lodash");

const array1 = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];

const array2 = [
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];

const mergedArray = [...array1, ...array2];

const uniqueArray = _.uniqBy(mergedArray, "id");

console.log(uniqueArray);

取出两个纯数组的不同元素

// 取出两个数组的不同元素
var arr1 = [0, 1, 2, 3, 4, 5];
var arr2 = [0, 4, 6, 1, 3, 9];

function getArrDifference(arr1, arr2) {
  return arr1.concat(arr2).filter(function (v, i, arr) {
    return arr.indexOf(v) === arr.lastIndexOf(v);
  });
}
console.log(getArrDifference(arr1, arr2)); //输出:(4) [2, 5, 6, 9]
console.log(getArrDifference(arr2, arr1)); //输出:(4) [6, 9, 2, 5]

取出两个纯数组的不相同元素

var arr1 = [0, 1, 2, 3, 4, 5];
var arr2 = [0, 4, 6, 1, 3, 9];

function getArrEqual(arr1, arr2) {
  let newArr = [];
  for (let i = 0; i < arr2.length; i++) {
    for (let j = 0; j < arr1.length; j++) {
      if (arr1[j] === arr2[i]) {
        newArr.push(arr1[j]);
      }
    }
  }
  return newArr;
}
console.log(getArrEqual(arr1, arr2)); //输出:(4) [0, 4, 1, 3]
console.log(getArrEqual(arr2, arr1)); //输出:(4) [0, 1, 3, 4]

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录