JavaScript实现数组扁平化、数组去重

330 阅读3分钟

数组去重

1. 双重循环比较

function remove(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
    for (var j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        i++
        j = i
      }
    }
    newArr.push(arr[i])
  }
  return newArr;
}

2.遍历数组+indexOf

var arr = [2, 8, 5, 0, 5, 2, 6, 7, 2]
function remove(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
  // indexOf()方法如果查询到则返回查询到的第一个结果在数组中的索引,如果查询不到则返回-1
  if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i])
    }
  }
  return newArr;
}
console.log(remove(arr)) // 结果:[2, 8, 5, 0, 6, 7]

3.数组下标判断法

如果在arr数组里面找当前的值,返回的索引等于当前的循环里面的i的话,那么证明这个值是第一次出现,所以推入到新数组里面,如果后面又遍历到了一个出现过的值,那也不会返回它的索引。

function remove(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
  if (arr.indexOf(arr[i]) === i) {
      newArr.push(arr[i])
    }
  }
  return newArr;
}

4. 排序后相邻比较去除法

function remove(arr) {
  arr.sort();               // 先排序,遍历按顺序比较
  var newArr = [arr[0]]     // 初始化arr[0]
  for (var i = 1; i < arr.length; i++) {
    if (arr[i] !== newArr[newArr.length - 1]) {
      newArr.push(arr[i])
    }
  }
  return newArr;
}

数组扁平化方法

数组扁平化概念:数组扁平化是指将一个多维数组降维成一维数组:

[1, [2, 3, [4, 5]]]  ------>    [1, 2, 3, 4, 5]

1.遍历数组+递归

基本思路:遍历数组,如果数组中还有数组的话,递归调用flatten扁平函数,用concat连接,返回结果。

let arr = [1, [2, 3, [4, 5]]];
const flatten = (arr) => {
  let res = [];
  for(const item of arr) {
    if(Array.isArray(item)) {
      res = res.concat(flatten(item));  // 递归调用flatten扁平函数
    } else {
      res.push(item);
    }
  }
  return res;
}
console.log(flatten(arr));    // [ 1, 2, 3, 4, 5 ]

2.迭代方法

function flatten2(arr) {
  const queue = [...arr];   // 用队列实现
  const res = [];
  while (queue.length) {
    const next = queue.shift();   // 从队列里取出
    if (Array.isArray(next)) {
      queue.push(...next);    // 把next扁平化,然后放入queue中
    } else {
      res.push(next);
    }
  }
  return res;
}
function flatten2(arr) {
  const stack = [...arr];
  const res = [];
  while (stack.length) {
    const next = stack.pop();       // 从栈里取出
    if (Array.isArray(next)) {
      stack.push(...next);         // 把next扁平化,然后放入stack中
    } else {
      res.push(next);
    }
  }
  return res.reverse();     // 翻转一下顺序 
}

基本思想就是,先把arr中的东西都放入stack中,然后不停pop stack中的东西。如果pop出来的是一个数组,那么把数组扁平化,再放入stack中;如果pop出来的不是数组,那么放入res中。

3.reduce方法

实现思路:使用reduce进行归并,如果数组中还有数组的话,递归调用flatten扁平函数。用concat连接,返回结果。

const flatten = (arr) => {
  return arr.reduce((res, item) => {
    return res.concat(Array.isArray(item) ? flatten(item) : item);  
  },[]);
}
console.log(flatten(arr));  //[ 1, 2, 3, 4, 5 ]

reduce方法会迭代数组的所有项,并在此基础上构建一个最终返回值。该方法接收两个参数:对每一项都会运行的归并函数(回调函数),以及可选的并以之为归并起点的初始值

// 例:求数组的各项值相加的和
let sum = arr.reduce((prev, cur)=> {  
  return prev + cur;
},0);

4.toString()+split()

调用数组的toString()方法,将数组变成字符串然后再用split()分割还原为数组。split()方法会根据传入的分隔符将字符串拆分成数组。

const flatten = (arr) => {
  return arr.toString().split(',').map(item => {
    return parseInt(item);
  })
}
console.log(flatten(arr));  // [ 1, 2, 3, 4, 5 ]

因为split分割后形成的数组(["1", "2", "3", "4", "5"])的每一项值为字符串,所以用map方法遍历数组将其每一项转换为数值类型。

5.join()+split()

和上面的toString()一样,join()也可以将数组转换为字符串。

const flatten = (arr) => {
  return arr.join(',').split(',').map(item => {
    return parseInt(item);
  })
}
console.log(flatten(arr));

6.展开运算符

ES6中对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。这里参数对象是个数组,数组里面的所有对象都是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。

let array = [1,2,3,4];
let copy = [...array];  //可以用展开运算符赋值数组
console.log(copy);    // [ 1, 2, 3, 4 ]

var arr = [1,[2,3],[4,5]];
let res = [].concat(...arr); //利用扩展运算符将二维数组变为一维
console.log(res);   // [ 1, 2, 3, 4, 5 ]

根据以上结果的启发,如果arr中含有数组则使用一次展开运算符,逐层击破,用concat连接,返回最终结果。

function flatten(arr){
  while(arr.some(item => Array.isArray(item))){
      arr = [].concat(...arr);
      // [ 1, [ 2, 3, [ 4, 5 ] ] ]
      // [ 1, 2, 3, [ 4, 5 ] ]
      // [ 1, 2, 3, 4, 5 ]
  }
  return arr;
}
console.log(flatten(arr));    // [ 1, 2, 3, 4, 5 ]

reduce方法详解可以看这篇

本文参考:js5种方法实现数组扁平化