zoukankan      html  css  js  c++  java
  • 添零占位 —— 快速生成N个0的六种办法

    做报表的时候偶尔会遇到这种需求:

    为了补齐长度,在一个数字字符串前面添加 N 个 0 占位

    举个例子:

    单元格需要展示 6 位数字,如 '123456'

    但后端返回的数字是 123,这时候就要在前面补 0,得到 '000123',使其长度为 6

    那就需要实现一个方法,基于 number 类型的参数 n,返回由 n 个 0 组成的字符串

    以及,在众多方案中,哪一个方案的耗时最短?

    测试模板:

    // pad_start.js
    
    function getPlaceholder(n, mark = '0') {
      // ...
    }
    
    function padStart(num, len) {
      const length = len - String(num).length;
      return length > 0 ? `${getPlaceholder(length)}${num}` : `${num}`;
    }
    
    console.time("Running");
    const str = padStart(123, 10000000);
    console.log('字符长度:', str.length.toLocaleString());
    console.timeEnd("Running");

    在模板代码中,需要实现 getPlaceholder 方法来添零占位,然后统计补全千万长度的数字需要多少时间

    方案一:for 循环

    function getPlaceholder(n, mark = '0') {
        let str = '';
        for (let i = 0; i < n; i++) {
            str += mark;
        }
        return str;
    }

    作为兜底方案,for 循环可能会迟到,但从不缺席...

      

    方案二:Math.pow

    function getPlaceholder(n) {
        return Math.pow(10, n).toString().slice(1);
    }

    由于需求是添“0”占位,可以取个巧,通过 Math.pow() 生成 10 的倍数,然后删掉首位的“1”,就得到了一串“0”

    不过如果数值过大,JS 会使用科学计数法,所以这里最健壮的写法应该是:

    function getPlaceholder(n) {
        return Math.pow(10, n).toLocaleString('zh-CN').replace(/,/g, '').slice(1);
    }

    即便如此,由于 JS 存在数值上限 Number.MAX_VALUE,所以 Math.pow(10, 309) 的结果为 Infinity,当字符长度超过 308 时就无法使用该方案

    这种方案的局限性太大,除了上面说的情况以外,如果需要使用“0”以外的占位符就用不了

    所以就不对该方案测速了...

     

    方案三:Number.toFixed

    function getPlaceholder(n) {
        return (1).toFixed(n).replace('.', '').slice(1);
    }

    如果对一个整数调用 toFixed,小数点后会用 0 来补位。基于这个特性可以很方便的生成一串“0”

    和方案二类似,这种方案只适用于用“0”占位的场景

    而且 toFixed 的入参只能是 0 ~ 100 的数字,无法处理超长的字符串,所以也不测速了...

     

    方案四:Array.fill

    function getPlaceholder(n, mark = '0') {
        return Array(n).fill('0').join('');
    }

    生成一个长度为 n 的数组,然后将元素都设为“0”,最后通过 join 拼成字符串

    比较全面的方案,相对简洁,也可以自定义占位符

    除了 Array.fill 之外,还可以使用其他方法,如 Array.from、Array.map

    这种方案的速度就快多了,比 for 循环节省了近六成的时间

      

    方案五:Array.join

    function getPlaceholder(n, mark = '0') {
        return Array(n + 1).join(mark);
    }

    方案四的进化版,new Array 之后会生成由 empty 构成的数组,可以直接对该数组做 join

    有一点需要注意,生成的数组长度得是 n + 1,因为 join 是对数组元素的间隙做填充

    相比于方案四,少了一次 Array.fill(),所以速度明显提升

     

    方案六:String.padStart

    ES2017 新增的方法,可以直接完成字符串的填充,参考 MDN > padStart

    const num = 123;
    // 下面的 8 是总长度
    String(num).padStart(8, "0");
    // "00000123"

    类似的还有 padEnd

    对该方案的测试,需要稍微修改下测试模板的代码:

    console.time("Running");
    const str = String(123).padStart(10000000, "0");
    console.log('字符长度:', str.length.toLocaleString());
    console.timeEnd("Running");

    这速度离谱吗?确实离谱!但这不是最离谱的...

    我把字符长度从一千万逐步加到十亿,耗时居然没啥变化 ?!

    可惜我翻遍了各种资料,也没查到如此高效的 String.padStart 是如何实现的...

    如果有小伙伴知道原因,请一定给我留言,或者来一发传送门,拜谢~

  • 相关阅读:
    [one day one question] safari缓存太厉害
    对工厂方法模式的一些思考(2)
    对工厂方法模式的一些思考(java语法表示)
    [选译]MySQL5.7以上Zip版官方安装文档
    clojure 使用阿里云仓库
    对jbox2d引擎的一些回顾与思考(swing实现demo)
    定位
    空白空间及溢出的处理
    BFC
    高度自适应
  • 原文地址:https://www.cnblogs.com/wisewrong/p/15353878.html
Copyright © 2011-2022 走看看