JS算法

/**
 * @description 数组去重
 * @param {number[]} arr
 */

exports.uniqueByObj = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    // 利用object的属性key不能相同特点来进行筛选
    let hash = {}
    let results = []
    for(let i = 0; i< arr.length; i++) {
        if(!hash[arr[i]]) { //!hash[arr[i] 为 true
            hash[arr[i]] = true
            results.push(arr[i])
        }
    }
    return results
}

exports.uniqueByIndexOf = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    // 数组下标判断法,当值不在新数组时,就加入该数组,如果在就不加了
    let results = []
    for(let i = 0; i < arr.length; i++) {
        if(results.indexOf(arr[i]) === -1) {
            results.push(arr[i])
        }
    }
    return results
}

exports.uniqueByTwoLoop = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    // 优化遍历数组法(推荐) 双层循环,(检测到有重复值时终止当前循环同时进入外层循环的下一轮判断)
    let results=[];
    for (let i = 0; i < arr.length; i++) {
      for (let j = i+1; j < arr.length; j++) {
        if(arr[i] === arr[j]){
          ++i;
        }
      }
      results.push(arr[i]);
    }
    return results;
}

exports.uniqueBySet = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    // ES6中的Set数据结构,类似于数组,它的成员都是唯一的 ,其构造函数可以接受一个数组作为参数
    // ES6中Array新增了一个静态方法Array.from,可以把类似数组的对象转换为数组
    let set = new Set(arr)
    return Array.from(set)
}

exports.uniqueBySetSimple = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    return [...new Set(arr)]
}

exports.uniqueByIncludes = (arr) => {
    if(!Array.isArray(arr)) {
        console.log('type error')
        return
    }
    let results = []
    for(let i=0;i<arr.length;i++) {
        if(!results.includes(arr[i])) { // includes检测数组是否有某个属性值
            results.push(arr[i])
        }
    }
    return results
}
/**
 * @description 数组排序算法, 冒泡排序
 * @param {number[]} arr
 */

 exports.bubbleSort = (arr) => { // 冒泡排序
    for(let i = 0; i < arr.length - 1; i++) {
        for(let j = i+1; j < arr.length; j++) {
            if(arr[i] > arr[j]) { //相邻元素两两对比
                let tem = arr[i] //元素交换
                arr[i] = arr[j]
                arr[j] = tem
            }
        }
    }
    return arr
 }
exports.bubbleSort1 = arr => { // 这种方式比上一种更快 当i=0的时候,里面的循环完整执行,从j=0执行到j=6,这也就是第一遍排序,结果是将最大的数排到了最后
  // 当i=1的时候,里面的循环再次完整执行,由于最大的数已经在最后了,没有必要去比较数组的最后两项,这也是j<arr.length-1-i的巧妙之处
  for(let i = 0; i < arr.length - 1; i++) {
    for(let j = 0; j < arr.length - 1 - i; j++) {
      if(arr[j] > arr[j+1]) {
        let temp = arr[j]
        arr[j] = arr[j+1]
        arr[j+1] = temp
      }
    }
  }
  return arr
}
 /**
 * @description 快速排序, 对冒泡排序的改进
 * @param {number[]} arr
 */
exports.quickSort = (arr) => {
    if(arr.length <= 1) {
        return arr
    }
    let pivotIndex = Math.floor(arr.length / 2)
    let pivot = arr.splice(pivotIndex, 1)[0]
    let left = []
    let right = []
    for(let i=0;i<arr.length;i++) {
        if(arr[i] < pivot) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return quickSort(left).concat([pivot],quickSort(right));
}
/**
* @description 选择排序
* @param {number[]} arr
*/
exports.selectSort = arr => {
  let minIndex, temp
  for(let i = 0;i < arr.length - 1; i++) {
    minIndex = i
    for(let j = i + 1; j < arr.length; j++) {
      if(arr[j] < arr[minIndex]) {
        minIndex = j
      }
    }
    temp = arr[i]
    arr[i] = arr[minIndex]
    arr[minIndex] = temp
  }
  return arr
}
/**
 * @description 水仙花数,水仙花数是一种特殊的三位数,它的特点就是,每个数位的立方和,等于它本身
 * @param {number} num
 */

 exports.daffodil = (num) => {
     let results = []
     for(let i=100;i<num;i++) {
        let nUnit = parseInt(i % 10) // 个位
        let nTen = parseInt((i / 10) % 10) // 十位
        let nHundred = parseInt((i / 100) % 10) // 百位
         if(Math.pow(nUnit, 3) + Math.pow(nTen, 3) + Math.pow(nHundred, 3) == i) {
            //  console.log(i)
            results.push(i)
         }
     }
     return results
 }

 /**
  * @description 给定数组,返回的两个数字之和等于目标数字
  * @param {number[]} nums
  * @param {number} target
  * @return {number[]}
  * Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1].
 */
exports.twoSum =(nums, target) => {
    let low = 0, high = nums.length -1;
    let sum = 0
    while(low < high) {
        sum = nums[low] + nums[high] // 数组两端的数字相加,与目标数字比较
        if(sum > target) { // 如果和大于目标数字,就将数组索引大的减少1
            high --
        } else if (sum < target) { // 如果和小于目标数字,就将数组索引大的加1
            low++
        } else { // 知道等于目标数字,输出此时数组的索引,记得都加1,或者知道索引大的等于索引小的,输出[-1, -1]
            return [low, high]
        }
    }
    return [-1, -1]
};

/**
 * @description 二分查找,非递归算法
 * @param {number[]} arr
 * @param {number} key
 */
// 在有序数组中查找特定元素的搜索算法, 返回目标元素索引值
exports.binarySearch = (arr, key) => {
    if(!contains(key)) {
        return
    }
    let low = 0, high = arr.length - 1
    while(low <= high) {
        let mid = parseInt((high + low) / 2)
        if(key == arr[mid]) {
            return mid
        } else if(key > arr[mid]) {
            low = mid + 1
        } else if(key < arr[mid]) {
            high = mid - 1
        } else {
            return -1
        }
    }
}

/**
 * @description 判断元素是否存在数组中
 * @param {number[]} arr
 * @param {number} obj
 */
const contains = function(arr, obj) {
    let i = arr.length;
    while (i--) {
      if (arr[i] === obj) {
        return true;
      }
    }
    return false;
}

/**
 * @description 阶乘 n! = n*(n-1)...21 , 6! = 6 * 5 * 4 * 3 * 2 *1
 * @param {number} number
 */
const factorial = function(number) {
    if(number == 1) {
        return number
    } else {
        // return number*factorial(number - 1)  or
        return number*arguments.callee(number - 1) // arguments.callee 表示拥有arguments对象的函数
    }
}
/**
 * @description 斐波那契数列
 * @param {number} number
 */
// 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... 求第n个数是多少
// 规律:后一项是前两项的和
const fibonacci = function(number) {
    if(number <= 2) {
        return 1
    }
    return fibonacci(number - 1) + fibonacci(number - 2)
}


/*
* 删除数组对象中多个数组元素
* { list } 数组对象 [{},{}]
* { currentSelected } 数组对象 [{},{}]
*/
const updataSearchList = (list, currentSelected) => {
    for(var i = 0;i<list.length;i++) {
        for(let j=0;j<currentSelected.length;j++) {
            if(list[i].contactId === currentSelected[j].contactId) {
                list.splice(i,1);
                i--;
            }
        }
    }
}

// ---------------------你不知道的js-------------------------------------------------------

function process(data) {
// 在这里做点有趣的事情
}
var someReallyBigData = { //.. };
process( someReallyBigData );
var btn = document.getElementById( "my_button" );
btn.addEventListener( "click", function click(evt) {
console.log("button clicked");
}, /*capturingPhase=*/false );

// click 函数形成了一个覆盖整个作用于的闭包,JS引擎极有可能依然保存着 someReallyBigData

/*
* 为变量显式声明块作用域, 就可解决
*/
function process(data) {
// 在这里做点有趣的事情
}
// 在这个块中定义的内容可以销毁了!
{
let someReallyBigData = { //.. };
process( someReallyBigData );
}
var btn = document.getElementById( "my_button" );
btn.addEventListener( "click", function click(evt){
console.log("button clicked");
}, /*capturingPhase=*/false );

/*
  函数声明和变量声明都会被提升 函数会首先被提升,然后才是变量 重复的声明会被忽略
*/



/*
  闭包-----当函数可以记住并访问所在词法作用域时, 就产生了闭包, 即使函数实在当前词法作用域之外
*/
function foo() {
  var a = 2
  function bar() {
    console.log(a)
  }
  return bar

}
foo()(); // 调用内部的bar 朋友 这就是闭包

// 无论以何种方式对函数类型的值进行传递,当函数在别处被调用都可以观察到闭包

function foo() {
  var a = 2
  function baz () {
    console.log(a)
  }
  bar(baz)
}
foo()
function bar(fn) {
  fn(); // 妈妈快看呀,这就是闭包!
}

// 传递函数当然也可以是间接的
var fn
function foo() {
  var a = 1
  function bar() {
    console.log(a)
  }
  fn = bar; // 将baz 分配给全局变量
}

foo()
fn()
/*
  只要使用了回调函数,实际上就是在使用闭包!
*/

// console.log(typeof(null))
/*
  不同的对象在底层都表示为二进制,在JavaScript 中二进制前三位都为0 的话会被判
  断为object 类型,null 的二进制表示是全0,自然前三位也是0,所以执行typeof 时会返回“object”。
*/

/*
  将两级数组平铺成一级
*/
var children = ['a','b',['c','d']]
function toOneLevel(children) {
  for (var i = 0; i < children.length; i++) {
    if (Array.isArray(children[i])) {
      return Array.prototype.concat.apply([], children)
    }
  }
}
// ["a", "b", "c", "d"]

/*
筛选数组对象
a: [{guid: '1'}, {guid: '2'},{guid: '4'}, {guid: '3'}]
b: [{guid: '1'}, {guid: '3'}]
结果: {guid: '2'},{guid: '4'}
*/
var c = a.filter(item => b.map(itemB => {
    return itemB.guid
}).indexOf(item.guid) < 0)

// 如果有不断变化的数字,只取前一个和当前值
let arr = [0, 0] 默认是0
function foo (data) {
  arr. shift() 删掉第一个元素
arr[1] = data
}
/**
 * @description 将数组平铺到指定的深度
 */
const flatten = (arr, depth = 1) => 
    depth != 1 ? arr.reduce((a, v) => a.concat( Array.isArray(v) ? flatten(v, depth - 1) : v), [])
    : arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v) : v), [])
/**
 * @description 将数组扁平化并去重排序
 */
function flatten(arr) {
    const res = arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v) : v), [])
    return Array.from(new Set(res)).sort((a, b) => a - b)
}
或者用 内置的flat(Infinity)平铺数组

/**
 * @description 取整 | 0
 */
const getInt = num => num | 0

// 截取数组,按照给定的数字
function sliceArray (num) {
  let result = []
  for (let i=0;i < arr.length; i++){
    if(i % num === 0) {
        result.push(arr.slice(i, i + num))
    }
  }
}

// 取前一个和当前的元素
let arr = [] // 放在外面
function foo(value) {
  arr.shift()
  arr[1] = value
}

// 创建随机数
  rndId (n) {
      let rnd = ''
      for(let i = 0; i < n; i++)
        rnd += Math.floor(Math.random() * 10)
      return rnd
    },
    /**
     * @description 数字转为字母
     * @param {Number} n 数字
     */
    createCellPos( n ){
      const ordA = 'A'.charCodeAt(0)
      const ordZ = 'Z'.charCodeAt(0)
      const len = ordZ - ordA + 1
      let s = ''
      while( n >= 0 ) {
        s = String.fromCharCode(n % len + ordA) + s
        n = Math.floor(n / len) - 1
      }
      return s
    },

// 数组获取负索引
const negativeArray = els => new Proxy(els, {
  get: (target, k) => Reflect.get(target, +k < 0 ? String(target.length + +k) : k)
})
var arr = negativeArray([1,2,3,4])
arr[-1]

// 打乱数组
function shuffle (arr) {
    let len = arr.length
    let randomIndex = null
    let currentItem = null
    while (len) {
        // 获取最后一个元素之前的随机位置
        randomIndex = Math.floor(Math.random() * len--)
        currentItem = arr[len]
        arr[len] = arr[randomIndex]
        arr[randomIndex] = currentItem
    }
    return arr
}

// 获取url中的参数
  function parseQuery (query) {
    const reg = /([^=&\s]+)[=\s]*([^&\s]*)/g
    let obj = {}
    while (reg.exec(query)) {
      obj[RegExp.$1] = RegExp.$2
    }
    return obj
  }
parseQuery(window.location.search.substr(1))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容