美文网首页JavaScript 进阶营让前端飞
【重学】数组扁平化,乱序

【重学】数组扁平化,乱序

作者: woow_wu7 | 来源:发表于2019-08-09 21:11 被阅读0次

    目录:
    数组扁平化
    数组乱序
    reduce()的妙用
    git复习:rebase,cherry-pick

    (1)数组扁平化

    1. flat()
    - Array.prototype.flat()
    - 参数是:要拉平的层数
    - 参数是 Infinity 时表示不管嵌套多少层,都转成一元数组
    - flat() 不会改变原数组,该方法会返回一个新数组
    - 如果原数组有空位,flat()方法会跳过空位
    - 代码:
    const arr = [1, [2, 3, [4, 5, [6,7]]]] // [1,2,3,4,5,6,7]
    const res = arr.flat(Infinity) // 参数表示展开的层数,如果是Infinity表示不管多少层都转成一元数组
    console.log(res)
    
    
    2. flatMap()
    - flatMap()表示相对数组执行 map() 方法,在执行 flat()方法
    - 参数:第一个参数是一个遍历函数,函数的参数一次是 value index array
    - flatMap()方法还可以有第二个参数,用来绑定遍历函数里面的this
    - flatMap()也不会改变原数组,会返回一个新的数组
    - 注意:flatMap()默认之展开一层
    - 代码:
    const arr = [1, 2, 3]
    const res = arr.flatMap(i => [i, i*2]) // [1, 2, 2, 4, 3, 6]
    // 相当于:[[1, 2], [2, 4], [3, 6]]
    console.log(res)
    
    2. 递归
    recursion:递归
    
    const arr = [1, [2, 3, [4, [5]]]]
    function flat(arr) {
        let result = []
        for(let i = 0, len = arr.length; i < len; i++) {
            if(Array.isArray(arr[i])) { // 如果还是数组,递归
                result = result.concat(flat(arr[i]))
            } 
            else {
                result.push(arr[i])
            }
        }
        return result
    }
    const res = flat(arr)
    console.log(res)
    
    3. toString
    - 如果数组元素都是数值(注意所有的数组中的所有元素都要是数字),可以使用toString()
    - 然而这种方法使用的场景却非常有限,如果数组是 [1, '1', 2, '2'] 的话,这种方法就会产生错误的结果。
    
    
    const arr = [1, [2, 3, [4, [5]]]]
    function flat(arr) {
        return arr.toString().split(',').map(item => +item)
        //  arr.toString()数组的字符串形式,会展平。      =>  1,2,3,4,5
        // arr.toString().split(',')以,为分隔符,将字符串转成数组  ["1", "2", "3", "4", "5"]
        // +item相当于Number(item)
    }
    const res = flat(arr)
    console.log(res)
    
    4. 使用reduce()
    
    var arr = [1, [2, [3, 4]]];
    function flatten(arr) {
        return arr.reduce(function(prev, next){
            return prev.concat(Array.isArray(next) ? flatten(next) : next)
        }, [])
      // 这里指定了初始值是 []
      // prev = []
      // next = 1,因为prev初始值是空数组,所以next的初始值是 1
    
      // reduce((accumulate, currentValue, index, arr) => {....}, [])
      // 第一个参数:是一个函数
        // 第一个参数:累积变量,默认是数组的第一个元素
        // 第二个参数:当前变量,默认是数组的第二个元素
        // 第三个参数:当前位置(当前变量在数组中的位置)
        // 第四个参数:原数组
      // 第二个参数:累积变量的初始值,注意如果指定了初始值,那么当前变量就从数组的第一个元素开始
    }
    
    console.log(flatten(arr))
    
    4. 使用 ...展开运算符
    
    let arr = [1, [2, [3, 4]]];
    function flat(arr) {
      while (arr.some(item => Array.isArray(item))) { // 循环判断是不是数组,是数组就展开
        arr = [].concat(...arr); // 每次都扁平一层
      }
      return arr;
    }
    console.log(flat(arr))
    

    https://github.com/mqyqingfeng/Blog/issues/36

    (2)数组乱序

    • shuffle:洗牌
    前置知识:
    1. sort()
    - sort()默认是按字典就行排序,数字会先被成字符串,改变原数组,没有返回值
    - 如果想按照自定义的方式排序,参数可以是一个函数
    - 参数函数有两个参数(两个比较的数组成员)
        - 返回值大于0,表示第一个成员排在第二个成员后面 (a-b>0,则a排在b后面)
        - 返回值小于0,表示第一个成员排在第二个成员前面
        - 返回值等于0,位置不变
    - arr.sort((a, b) => a - b ) 升序
    - arr.sort((a, b) => b - a ) 降序
    
    
    2. js中不加分号的注意事项:
    - 小括号开头的前一条语句(注意前面要是语句,表达式不受影响)
    - 中括号开头的前一条语句
    解决方法:在小括号或者中括号前面加上分号
    
    
    哪些地方会用到乱序:
    1. 换一批
    2. 猜你喜欢
    3. 中奖方案
    
    
    方法1:
    arr.sort(() => Math.random() - .5)
    
    
    function a() {
      const arr = [1, 2, 3, 4, 5]
      arr.sort(() => Math.random() - .5)  // 因为Math.random的值区间是[0, 1) 所以 这里大于0和小于0的概率都是50%
      // sort自定义排序时接收一个函数作为参数
      // 函数返回值大于0,表示两个比较的成员,第一个排在第二个的后面
      // 函数返回值小于0,表示两个比较的成员,第一个排在第二个的前面
      // 函数返回值等于0,表示两个比较的成员,位置不变
      // 当小数是0点几时,可以省略前面的0
      console.log(arr)
    }
    
    
    -----------
    存在问题:
    1. 概率不均等
    2. 造成概率不均等的原因是,sort底层实现是用了插入排序
    3. 具体就是当无序部分插入到有序部分的元素,一旦找到位置,剩下的元素就没有在和缓存的值就行比较了
    4. 没有机会比较所有元素,所以得不到完全随机的结果
    如下:
    const times = [0, 0, 0, 0, 0, 0]
    for(i = 0; i < 100000; i++) {
        const arr = [1, 2, 3, 4, 5, 6]
        arr.sort(() => Math.random() - 0.5)
        times[arr[5] - 1] ++  
        // times[arr[5] - 1] ++ 表示arr数组最后一个位置上,各数字出现的次数
        // 当arr[5]是6时,times[5]位置的值+1,就是arr[5]是6的次数+1
    }
    console.log(times)
    // [19480, 5174, 15619, 14188, 18880, 26659] 概率分配不均,arr[5]是2的概率明显小了很多
    
    
    
    -----------
    sort排序源码:
    - 各个浏览器的sort()方法的实现方法不同
    - v8中
      - 当数组长度小于10时,用的是插入排序
      - 否则,使用的是插入排序和快速排序的混合排序
    
    
    
    -----------
    插入排序
    - 分类:
      - 直接插入排序:顺序发定位插入位置
      - 二分插入排序:二分法定位插入位置
      -   希尔排序  :缩小增量,多遍插入排序
    
    
    
    -----------
    直接插入排序:
    - 插入排序的思想:从无序数组中取出一个值,插入到有序数组中,插入后有序数组仍然有序(打牌)
    - 原理:
      1. 将数组分成两部分,左边是有序数组(最初只有一个元素),右边是无序数组(所以循环是从1开始,因为有序部分初始有一个元素)
      2. 从右边的无序部分依次取出一个值,插入到有序部分,直到取完无序部分
      3. 如果找有序部分的插入位置?:
        1. 先缓存需要插入的无序部分的值,用一个变量来缓存 let temp = arr[i]
        2. 从有序部分的最后位置找(arr[i - 1]),如果arr[i - 1] > arr[i] 则该元素往后移动一位
        3. 如果有序该位置仍然比需要插入的值大,有序中该位置的值,也后移动一位,直到 j>=0
    - 代码:
    // 直接插入排序
    const arr = [1, 4, 3, 2]
    const insert_sort = (arr) => {
        for(let i = 1, len = arr.length; i < len; i++) { // 循环数组的无序部分,从1开始,因为假设初始化时有序部分有一个元素
            let temp = arr[i] // 缓存需要插入有序部分的这个无序部分的值,因为有序部分可能会往后移动位置,将其覆盖
            let j = i - 1 // 有序部分的最后一个元素的位置,有序部分从最后的位置依次往前查找需要插入的位置
            while(j >= 0 && arr[j] > temp) { // 有序部分循环条件
                arr[j+1] = arr[j] // 有序该位置值大于temp,则往后移动一位
                j-- // 依次往前查找
            }
            arr[j+1] = temp // 循环完后,j+1就是需要插入的位置,因为条件是大于temp,不满足时,j+1就是要插入的位置
        }
        return arr // 最后返回数组
    }
    console.log(insert_sort(arr))
    

    乱序排序改进

    Fisher–Yates
    
    1. 使用sort(() =>  Math.random() - .5)存在的问题就是不能完全实现全部元素的比较,造成概率不均等
    2. 为什么叫 Fisher–Yates 呢?
      - 因为这个算法是由 Ronald Fisher 和 Frank Yates 首次提出的。
    3.shuffle:是洗牌的意思
    
    4.Fisher–Yates的原理:
    - 首先选取(数组最后一个位置)的元素和(数组长度随机位置)上的元素交换
    - 接着选取(数组倒数第二个位置)的元素和(除去最后一个位置剩下的数组位置)上的元素交换
    - 重复以上步骤,直到length >= 1
    
    5.代码
    // 数组乱序
    const arr = [1, 2, 3, 4, 5, 6]
    function shuffle(arr) {
        let length = arr.length
        while(length > 1) {
            const pivot = Math.floor(Math.random() * length--) 
            // 1. 注意这里是先赋值,再减 1,即Math.floor(Math.random() * 6) 
            // (Math.random() * 6的区间[0, 6)
            // Math.floor(Math.random() * 6) 区间是 [0-5]
    
            // 2. 语句以分号结尾,一个分号就表示一个语句结束。所以这里赋值语句后面记得加分号
            // 3. ;[arr[pivot], arr[length]] = [arr[length], arr[pivot]]这里条语句前加上分号,因为前面也是语句
            // 在小括号开头,或者中括号开头的语句,前面的语句末尾需要加分号,或者加到本条语句前面
            //4. const pivot = Math.floor(Math.random() * length--); 这样也行
            ;[arr[pivot], arr[length]] = [arr[length], arr[pivot]] // 这里的length是减1之后的length
            // const temp = arr[length]
            // arr[length] = arr[pivot]
            // arr[pivot] = temp
        }
        return arr
    }
    console.log(shuffle(arr))
    

    https://juejin.im/post/5d004ad95188257c6b518056#heading-2

    (3)reduce()使用技巧

    reduce()
    
    (1) 概念
    - reduce()默认按照字典排序
    - reduce(function(reduce, currentValue, currentIndex, arr), initial)
    - 第一个参数是函数:
      - 函数第一个参数:累计变量,默认是数组的第一项
      - 函数第二个参数:当前变量,默认是数组的第二项(如给定reduce第二个参数(累积变量初始值),则当前变量从第一项开始)
      - 函数第三个参数:当前位置,(第二个参数的下标)
      - 函数第四个参数:原数组
    - 第二个参数是(累计变量初始值),如果给定累计变量初始值,当前变量就从数组第一项开始
    
    (2) 用法
    1. 累加
    
    2. 将数组转化成对象
    const arr = [{id: 1, name: 'wang'}, {id: 2, name: 'zhang'}]
    const res = arr.reduce((pre, cur, i, arr) => {
      return {...pre, [cur.id]: cur}
    }, {})
    console.log(res)
    
    
    (3) 实现数组扁平化
    const arr = [1, [2, [3, [4, 5]], 6], 7]
    function flat(arr) {
      return arr.reduce((prev, current, index, arr) => {
        return prev.concat(Array.isArray(current) ? flat(current) : current)
      }, [])
    }
    const res = flat(arr)
    console.log(res)
    

    https://juejin.im/post/5cbc23def265da037b610ec6#heading-18

    https://juejin.im/post/5d073414f265da1b6029037f

    (4)git

    (一)初次运行git前的配置
    
    (1) 用户信息
    - 第一步就是设置(用户名)和(邮件地址)
    - 如果使用了--global,该命令只需运行一次,之后无论在什么系统上做任何事情,git都会使用那些信息
    - 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。
    $ git config --global user.name "John Doe"
    $ git config --global user.email johndoe@example.com
    
    
    (2) 文本编辑器
    - 当用户信息配置完后,可以配置文本编辑器,用户使用git输入信息时,会调用文本编辑器
    - 默认调用的是 (vim),如果想自定义可以输入以下命令:
    $ git config --global core.editor emacs  // 使用Emacs编辑器
    
    
    (3) 检查配置信息
    - 如果想要检查你的配置,可以使用 git config --list 命令来列出所有 Git 当时能找到的配置
    $ git config --list
    
    (1) git log
    - git log:显示从最近到最远的提交日志
    - git log --pretty=oneline --graph
    - // --pretty=oneline 将commit 信息简化成一行显示
    - // --graph命令可以看到分支合并图。 -------------( graph是图表的意思 )
    
    
    (2) git reflog
    - gitt reflog:记录几乎所有本地仓库的改变
    - 可以用来重返未来(git reset --hard comit_id之后后悔)
    
    
    (3) git reset
    - git reset --hard commit_id
    - git reset --hard HEAD^ // 回退到上一个commit
    - 当前版本   ( HEAD )
    - 上一个版本 ( HEAD^ )或者  ( HEAD~1 )
    - 上上个版本 ( HEAD^^ ) 或者 ( HEAD~2 )
    
    (4) git rebase
    - 不同分支:变基
    - 同一分支:合并多个提交
    
    git rebase变基
    - 不同分支的处理是变基
    - git rebase master  // 把当前分支变基到master分支
    
    git rebase进入交互模式 
    - 同一分支是进入交互模式
    
    - git rebase -i  [startpoint]  [endpoint] 
    - git rebase -i HEAD~3  表示将最新的三个提交进入交互式界面
    // [startpoint]  [endpoint]这个是一个 (前开后闭区间)
    // 如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(
    // i:是 (interactive)交互的意思
    
    pick:保留该commit(缩写:p)
    reword:保留该commit,但我需要修改该commit的注释(缩写:r)
    edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
    squash:将该commit和前一个commit合并(缩写:s)
    fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
    exec:执行shell命令(缩写:x)
    drop:我要丢弃该commit(缩写:d)
    
    - squash:是粉碎的意思
    - reword:改写,修改措辞的意思
    

    https://www.jianshu.com/p/4a8f4af4e803

    https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%88%9D%E6%AC%A1%E8%BF%90%E8%A1%8C-Git-%E5%89%8D%E7%9A%84%E9%85%8D%E7%BD%AE

    (5) git cherry-pick 摘樱桃
    - git cherry-pick:把其他分支的commit,移到当前分支
    - git cherry-pick <commit id>
    
    - 如果有冲突,首先需要解决冲突,解决冲突后需要git commit手动进行提交
    - git add .后直接使用git cherry-pick --continue继续 // 继续后,可以修改提交的commit的命名
    

    https://www.cnblogs.com/ludashi/p/8213550.html

    相关文章

      网友评论

        本文标题:【重学】数组扁平化,乱序

        本文链接:https://www.haomeiwen.com/subject/geksdctx.html