【问题标题】:how to reduce numbers' significance in JSON's stringify如何降低 JSON stringify 中数字的重要性
【发布时间】:2012-03-09 12:55:45
【问题描述】:

我有一个带有数字(坐标)的数组,我想像这样使用 JSON 显示这些数组

 JSON.stringify(array);

我的数组看起来像:

[{"x":-0.825,"y":0},
 {"x":-1.5812500000000003,"y":-0.5625},
 {"x":-2.2515625000000004,"y":-1.546875}]

但我只对第一个(比方说)4 个有效数字感兴趣,即

[{"x":-0.825,"y":0},
 {"x":-1.5813,"y":-0.5625},
 {"x":-2.2516,"y":-1.5469}]

有没有办法轻松抛弃剩余的无关紧要的数字?

【问题讨论】:

    标签: javascript json number-formatting


    【解决方案1】:

    遍历您的数组并将以下内容应用于所有值。

     value = Math.round( value * 10000 ) / 10000;
    

    另一种可能性是将您的坐标在内部存储为 int 值(10^-4 的倍数),然后将它们转换为输出。

    【讨论】:

    • 这在很多(大多数?)情况下都不起作用(因为浮点数在内部存储的方式)
    【解决方案2】:

    使用Number#toPrecisionNumber#toFixed,以更适合您的需要为准。区别在于toFixed设置小数点后的位数,toPrecision设置整数位数。

    var foo = 1.98765432; 
    console.log(foo.toPrecision(5)); // 1.9877
    

    请注意,toFixedtoPrecision 返回字符串,因此您可能需要在将它们 JSON 化之前将它们转换回数字。

    这是强制性的MDN link


    如果你想自己动手,你也可以这样做。

    Math.round(1.98765432 * 10000) / 10000 // 1.9877
    

    封装在一个函数中,它可能看起来像这样:

    function precisify(n, places) { 
        var scale = Math.pow(10, places); 
        return Math.round(n * scale) / scale; 
    }
    

    【讨论】:

    • 请注意,toFixedtoPrecision 返回字符串,而不是数字。因此,您需要强制转换(通过以一元 + 为前缀)以将它们保留为数字。
    • @Dave,说得好。它不太适合我的简单示例,所以我把它省略了,但我想我应该提一下。
    • 有人对此进行了基准测试吗?就速度而言,它是否会大大减慢字符串化速度?在某些情况下,它可以将 5MB 的数据减少到仅 2.5MB。但如果 stringify 慢了 100 毫秒,那可能就不值得了。
    【解决方案3】:

    首先想到的方法是对数组进行预处理,将所有数字四舍五入:

    var array =[{"x":-0.825,"y":0},
                {"x":-1.5812500000000003,"y":-0.5625},
                {"x":-2.2515625000000004,"y":-1.546875}];
    
    ​for (​var i=0; i<array.length; i++){
        array[i].x = +array[i].x.toFixed(4);
        array[i].y = +array[i].y.toFixed(4);
    }
    
    var json = JSON.stringify(array);
    
    // json === '[{"x":-0.825,"y":0},{"x":-1.5813,"y":-0.5625},{"x":-2.2516,"y":-1.5469}]'
    

    .toFixed() function 返回一个字符串,所以我使用一元加号运算符将其转换回数字。

    想到的第二种方式是处理JSON.stringify()输出的字符串:

    json = json.replace(/(\.\d{4})(\d+)/g,"$1");
    

    【讨论】:

      【解决方案4】:

      有点矫枉过正,但这应该适用于所有情况。

      function prepareArrayForJSON(array) {
          var i = 0;
          while (i < array.length) {
              if (typeof array[i] === 'number') {
                  array[i] = array[i].toPrecision(4);
              } else if(typeof array[i] === 'object') {
                  if (array instanceof Object) {
                      prepareObjectForJSON(array[i]);
                  } else if (array instanceof Array) {
                      prepareArrayForJSON(array[i]);
                  }
              }
          }
      }
      
      function prepareObjectForJSON(obj) {
          var i;
          for (i in obj) {
              if (obj.hasOwnProperty(i)) {
                  if (typeof obj[i] === 'number') {
                      obj[i] = obj[i].toPrecision(4);
                  } else if(typeof obj[i] === 'object') {
                      if (obj instanceof Object) {
                          prepareObjectForJSON(array[i]);
                      } else if (obj instanceof Array) {
                          prepareArrayForJSON(obj[i]);
                      }
                  }
              }
          }
      }
      

      尽情享受

      【讨论】:

      • 这个问题的答案数量太多了。我想我最喜欢你的选择,因为它是最通用的。我希望在 JSON 的 stringify 中有额外的参数选项,但显然这是不可能的。
      【解决方案5】:

      Native JSON.stringify 接受参数replacer,它可以是将值转换为所需值的函数:

      a = [0.123456789123456789]
      JSON.stringify(a, function(key, val) {
          return val.toFixed ? Number(val.toFixed(3)) : val;
      })
      
      >> "[0.123]"
      

      【讨论】:

      • 很好的答案。如果您正在转换 GeoJSON 文件,只是一个小补充:上面不仅会转换坐标,还会转换所有属性。因此我在 return 语句之前添加了if (isNaN(+key)) return val;,因为数组中的键是它的索引。
      • 既然JSON.stringify 会将所有内容都转换为字符串,那么将toFixed 的输出转换为数字有什么意义呢?即,为什么Number(val.toFixed(3)) 而不仅仅是val.toFixed(3)
      • 回答我自己的问题:因为如果替换是一个字符串,stringify 在 JSON 中的替换周围加上引号,导致接收者将其解释为字符串而不是数字。
      • @EdwardBrey:没错,Number(val.toFixed(n)) 是一种将数字四舍五入到 n 位小数的廉价方法。
      • @georg 创建一个字符串并解析它并不便宜,但它是 JavaScript 缺乏原生舍入机制的一种解决方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      相关资源
      最近更新 更多