(扁平,去重,排序)=>管道函数

225 阅读3分钟

数组扁平化就是将 [1, [2, [3]]] 这种多层的数组拍平成一层 [1, 2, 3]

实现数组扁平化的5种方法:

1、使用数组原型上的flat方法:

使用 Array.prototype.flat 可以直接将多层数组拍平成一层:
console.log([1, [2, [3]]].flat(2))  // [1, 2, 3]  flat(2) 2是深度 无限深度:flat(Infinity)

2、递归遍历:

function flatten(arr) {
  let newArr = [];
  arr.forEach(value => {
    if (Array.isArray(value)) {
      newArr = newArr.concat(flatten(value));
    } else {
      newArr = newArr.concat(value);
    }
  })
  return newArr;
}
let arr = [1, 2, 3, [4, 5], [6, [7, 8]],];
console.log(flatten(arr));

3、使用ES6的reduce函数:

function flatten(arr) {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flatten(cur) : cur)
  }, [])   //是数组就会递归调用这个方法,[1, [2, [3]]] => 1取出,[2, [3]] => 2取出,[3]
}
console.log(flatten([1,[2,[3]]]))

4、while循环结合some与扩展运算符:

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

5、数组强制类型转换:

function flatten(arr){
  return arr.toString().split(',').map(Number)
}
let arr = [1, 2, 3, [4, 5], [6, [7, 8]],];
console.log(flatten(arr));

实现数组去重的5种方法:

1、利用ES6的Set方法:

[...new Set(arr)]
// or
Array.from(new Set(arr))  //new Set(arr)结果不是一个数组,Array.from将它转换为数组

2、数组的includes方法:

function removeRepeat(arr) {
    let newArr = [];
    for (let i=0; i<arr.length; i++) {
        //方法一
        // if(newArr.indexOf(arr[i]) === -1){
        //     newArr.push(arr[i]);
        // }
        //方法二
        if(!newArr.includes(arr[i])) {
            newArr.push(arr[i]);
        }
    }
    return newArr;
}
var arr = [8,11,20,5,20,8,0,2,4,0,8,19];
console.log(removeRepeat(arr));

3、利用ES6的filter方法:

function unique(arr) {
    var res = arr.filter((item,index,array) => {
        return array.indexOf(item) === index
    })
    return res
}

4、使用filter和Map:

function unique(arr) {
    const map = new Map();
    return arr.filter((item) => !map.has(item) && map.set(item));
}
var arr = [8,11,20,5,20,8,0,2,4,0,8,19];
console.log(unique(arr));

5、使用reduce:

let arr = [1,2,2,3,4,5,5,5]
let removeRepeat = arr.reduce((pre,cur) => {
    if(!pre.includes(cur)){
        return pre.concat(cur)
    } else {
        return pre
    }
}, [])
console.log(removeRepeat);

排序算法:

稳定排序:冒插归基

不稳定排序:快选希堆

image.png

1、api sort()方法

const sort = (arr) => arr.sort((a, b) => a - b)

arr.sort((a,b) => a-b); //从小到大,对负数也行
arr.sort((a,b) => b-a); //sort()默认从小到大,此方法是从大到小 

2、冒泡排序 时间复杂度O(n^2) 空间复杂度O(1)

function bubbleSort(arr) {
  const len = arr.length-1
  // 外层循环用于控制从头到尾的比较+交换到底有多少轮
  for (let i = 0; i < len; i++) {
    // 内层循环用于完成每一轮遍历过程中的重复比较+交换
    for (let j = 0; j < len - i; j++) {
      // 若相邻元素前面的数比后面的大
      if (arr[j] > arr[j + 1]) {
        // 利用es6数组解构赋值交换两者
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
      }
    }
  }
  return arr
}

3、快速排序 时间复杂度O(nlogn) 空间复杂度O(logn)

const quickSort = function (arr) {
  if (arr.length <= 1) return arr  ///如果数组<=1,则直接返回,也是递归出口
  let pivotIndex = Math.floor(arr.length / 2)  //Math.floor()可以获得一个数的整数部分,而不是四舍五入
  //找基准,并把基准从原数组删除
  let pivot = arr.splice(pivotIndex, 1)[0]
  let left = [], right = []   //定义左右数组
  for (let i = 0; i < arr.length; i++) {   //比基准小的放在left,比基准大的放在right
    if (arr[i] < pivot) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  // 不断重复第一步和第二步,直到所有子集只剩下一个元素为止
  return quickSort(left).concat(pivot, quickSort(right))
}

快排-双指针法

function quickSort(arr, low, high) {
  let key = arr[low], start = low, end = high
  while (end > start) {
    while (end > start && arr[end] >= key) end-- //移动右指针
    if (arr[end] <= key) {
      [arr[end], arr[start]] = [arr[start], arr[end]]
    }
    while (end > start && arr[start] <= key) start++ //移动左指针
    if (arr[start] >= key) {
      [arr[start], arr[end]] = [arr[end], arr[start]]
    }
  }
  if (start > low) quickSort(arr, low, start - 1) //左边递归
  if (end < high) quickSort(arr, end + 1, high) //右边递归
  return arr
}
console.log(quickSort([4, 2, 1, 5, 3, 2], 0, 5)) //[ 1, 2, 2, 3, 4, 5 ]

4、插入排序 时间复杂度O(n^2) 空间复杂度O(1)

function insertSort(arr) {
  const handle = [arr[0]], len = arr.length
  for (let i = 1; i <= len - 1; i++) {
    const current = arr[i]
    for (let j = handle.length - 1; j >= 0; j--) {
      if (current > handle[j]) {
        handle.splice(j + 1, 0, current)
        break
      }
      if (j === 0) {
        handle.unshift(current)
      }
    }
  }
  return handle
}

插入排序-优化版

// 将arr[]按升序排列
function insertSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    //将arr[i]插入到arr[i-1],arr[i-2],arr[i-3]……之中
    for (let j = i; j > 0; j--) {
      if (arr[j] < arr[j - 1]) {
        [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]]
      }
    }
  }
  return arr
}

5、选择排序 时间复杂度O(n^2) 空间复杂度O(1)

// 第一个开始和一组中最小的交换,往后类推
function selectSort(arr) {
  const len = arr.length
  // 定义 minIndex,缓存当前区间最小值的索引,注意是索引
  let minIndex
  for (let i = 0; i < len - 1; i++) {
    // 初始化 minIndex 为当前区间第一个元素
    minIndex = i
    // i、j分别定义当前区间的上下界,i是左边界,j是右边界
    for (let j = i + 1; j < len; j++) {
      // 若 j 处的数据项比当前最小值还要小,则更新最小值索引为 j
      if (arr[minIndex] > arr[j]) {
        minIndex = j
      }
    }
    // 如果 minIndex 对应元素不是目前的头部元素,则交换两者
    if (minIndex !== i) {
      [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    }
  }
  return arr
}

管道函数

题目:

实现一个函数可以实现 数组扁平化和去重并排好序

一把嗦写法:

// 扁平+去重+排序
const fn = (arr) => {
  let arr2 = arr.flat(Infinity)
  let arr3 = [...new Set(arr2)]
  return arr3.sort((a, b) => a - b)
}
let arr = [[12, 2, 2], [6, 7, 8, 5], [3, 4, 5, 9, [10, 3, [1, 7, [11]]]]]
console.log(fn(arr))

这样子写的话, 不利于代码复用, 我们尽可能让一个函数只做一件事情, 所以可以将这个函数拆成三个函数, 然后再利用一个辅助函数让它依次执行

管道函数写法:

// 扁平
const flatten = (arr) =>
  arr.reduce((acc, v) => acc.concat(Array.isArray(v) ? flatten(v) : v), [])

// 去重
const unique = (arr) => [...new Set(arr)]

// 排序
const sort = (arr) => arr.sort((a, b) => a - b)

// 管道函数
const pipe = (...fns) =>
  fns.reduce((f, g) =>
    (...args) =>
      g(f(...args))
  )
console.log(pipe(flatten, unique, sort)(arr))

完结~