Skip to content

对象元素的数组去重实现

需求

有这样一个数组

javascript
[
  {
    _id: 123,
    name: "张三",
  },
  {
    _id: 124,
    name: "李四",
  },
  {
    _id: 123,
    name: "张三",
  },
];
[
  {
    _id: 123,
    name: "张三",
  },
  {
    _id: 124,
    name: "李四",
  },
  {
    _id: 123,
    name: "张三",
  },
];

实际上我们只需要

javascript
[
  {
    _id: 123,
    name: "张三",
  },
  {
    _id: 124,
    name: "李四",
  },
];
[
  {
    _id: 123,
    name: "张三",
  },
  {
    _id: 124,
    name: "李四",
  },
];

去重

简单数组的去重

javascript
Array.from(new Set([1, 1, 2, 3, 4, 4])); // [1,2,3,4]
Array.from(new Set([1, 1, 2, 3, 4, 4])); // [1,2,3,4]

以对象为元素的数组去重

和数组相关的算法多种多样,在你以为自己已经掌握数组之后,会发现很多和数组相关的算法仍旧很复杂。

下面我将讲述一个入门等级的数组算法,解决上面提出的需求。

1、定义一个函数 removeRepeat,它需要传入 2 个参数,arr 表示需要去重的数组,field 表示需要比较的 key。比如我们的需求是比较 _id 是否有重复。

javascript
function removeRepeat(arr, field) {
  return arr;
}
function removeRepeat(arr, field) {
  return arr;
}

2、需要一个空数组,用来存储每个对象元素中 field 对应的 value。

javascript
let s = [];
for (let v of arr) {
  s.push(v[field]);
}
//s = [123, 124, 123]
let s = [];
for (let v of arr) {
  s.push(v[field]);
}
//s = [123, 124, 123]

3、将所有 field 的值存到数组之后,它们的下标一一对应原数组的下标(这点很重要),接着我们需要 2 个对象集合,result 用来存储 s 里遍历出来的元素,如果有重复,就将重复的元素丢到 reSet 对象里面。

javascript
let result = {},
  reSet = {};
for (let i = 0, len = s.length; i < len; i++) {
  if (!result[s[i]] && result[s[i]] !== 0) {
    // 如果 result 不存在当前的 key 并且它不为 0 时
    result[s[i]] = i;
  } else {
    reSet[s[i]] = i;
  }
}
// result = {123: 0, 124: 1} 这是去重重复后的元素
// reSet = {123: 2} 我们将重复的元素 123 作为 key,它的下标 2 作为 value。
let result = {},
  reSet = {};
for (let i = 0, len = s.length; i < len; i++) {
  if (!result[s[i]] && result[s[i]] !== 0) {
    // 如果 result 不存在当前的 key 并且它不为 0 时
    result[s[i]] = i;
  } else {
    reSet[s[i]] = i;
  }
}
// result = {123: 0, 124: 1} 这是去重重复后的元素
// reSet = {123: 2} 我们将重复的元素 123 作为 key,它的下标 2 作为 value。

4、上一步得到了 result 和 reSet2 个对象,那么,我们该用哪个对象来处理原数组的去重呢?只需要 reSet,reSet 记录了要去重的对象所在的下标,那么可以直接用 splice 干掉它。

javascript
for (let key in reSet) {
  arr.splice(reSet[key], 1);
}
/*
arr = [{
    _id: 123,
    name: '张三'
},{
    _id: 124,
    name: '李四'
}]
*/
for (let key in reSet) {
  arr.splice(reSet[key], 1);
}
/*
arr = [{
    _id: 123,
    name: '张三'
},{
    _id: 124,
    name: '李四'
}]
*/

5、说明

关键的第 3 和 4 步,都是用对象来处理,这样做的好处是时间复杂度可以达到 O(1),如果用数组来保存,则需要 2 个 for 循环,时间复杂度变成了 O(n²)。

完整源码

javascript
function removeRepeat(arr, field) {
  let s = [],
    result = {},
    reSet = {};
  for (let v of arr) {
    s.push(v[field]);
  }
  for (let i = 0, len = s.length; i < len; i++) {
    if (!result[s[i]] && result[s[i]] !== 0) {
      result[s[i]] = i;
    } else {
      reSet[s[i]] = i;
    }
  }
  for (let key in reSet) {
    arr.splice(reSet[key], 1);
  }
  return arr;
}

// removeRepeat(arr, '_id')
function removeRepeat(arr, field) {
  let s = [],
    result = {},
    reSet = {};
  for (let v of arr) {
    s.push(v[field]);
  }
  for (let i = 0, len = s.length; i < len; i++) {
    if (!result[s[i]] && result[s[i]] !== 0) {
      result[s[i]] = i;
    } else {
      reSet[s[i]] = i;
    }
  }
  for (let key in reSet) {
    arr.splice(reSet[key], 1);
  }
  return arr;
}

// removeRepeat(arr, '_id')

最后编辑时间:

Version 4.0 (framework-1.0.0-rc.20)