经常会遇到一些业务场景会需要我们对一个数组进行去重,基本数据类型的一维数组比较好办,使用reduce方法扫一遍即可实现去重,但是很多时候是通过后端返回一些数据,如果后端没有进行去重的操作,那么就只能把锅甩到前端了。。。

场景

例如现在从后端接收到了一串数据:

  1. let arr = [
  2. {
  3. a: '1234',
  4. b: '5678'
  5. },
  6. {
  7. a: '1234',
  8. b: '56178'
  9. },
  10. {
  11. a: '1234',
  12. b: '5678'
  13. },
  14. {
  15. a: '1234',
  16. b: '51123678'
  17. },
  18. {
  19. a: '1234',
  20. b: 'abc'
  21. },
  22. {
  23. b: 'abc',
  24. a: '1234'
  25. }
  26. ]

里面有一些数据是重合的,因此需要进行去重处理,有些可能会立马想到使用JSON.stringify方法将两两转换成字符串做全等匹配,但是这样是不靠谱的,因为json对象中key是无序的,只要键值对稍微调换一下位置就会出错。
image.png
目前我只想到最笨的方法,就是利用冒泡排序的思想,将数组中所有的数据都进行两两匹配,将两个对象中的键值对依次匹配,如果两个对象中属性值相等的次数等于了对象中的所有属性个数,说明两个对象中的值完全相等。

方法1

  1. let flag = 0;
  2. for (let i = 0; i < arr.length; i++) {
  3. for (let j = i + 1; j < arr.length; j++) {
  4. let pre = arr[i];
  5. let next = arr[j];
  6. for (let key in pre) {
  7. // 有一个属性相等,flag+1
  8. if (pre[key] === next[key]) {
  9. flag++;
  10. }
  11. }
  12. // 如果相等的属性个数为一个对象的全部属性个数,说明完全重合
  13. if (flag === Object.keys(pre).length) {
  14. arr.splice(j, 1);
  15. }
  16. // 清除一个之后flag清零重新计数
  17. flag = 0;
  18. }
  19. }

方法2

  1. function isObjEqual(o1, o2) {
  2. let props1 = Object.getOwnPropertyNames(o1);
  3. let props2 = Object.getOwnPropertyNames(o2);
  4. if (props1.length !== props2.length) {
  5. return false;
  6. }
  7. for (let i = 0, max = props1.length; i < max; i++) {
  8. let propName = props1[i];
  9. if (o1[propName] !== o2[propName]) {
  10. return false;
  11. }
  12. }
  13. return true;
  14. }
  15. let newArr = arr.reduce((prev, cur) => {
  16. let flag = false;
  17. for (let i = 0, len = prev.length; i < len; i++) {
  18. if (isObjEqual(prev[i], cur)) {
  19. flag = true;
  20. }
  21. }
  22. if (!flag) {
  23. prev.push(cur);
  24. }
  25. return prev;
  26. }, [])

注意点

以上提到的两种方法仅针对于以上指定场景中的情况,并且对象中的属性个数完全相等,并且数组中每个对象中的值都为基本数据类型。