【问题标题】:How to flatten a clamped array如何展平钳位数组
【发布时间】:2016-10-31 13:09:29
【问题描述】:

此刻我发现自己被困在试图展平 Uint8ClampedArray。

起始数组结构是data = [227, 138, 255…],在从类似enc = [Uint8ClampedArray[900], Uint8ClampedArray[900], Uint8ClampedArray[900]...] 的数组创建数组后,我尝试将其展平。

为此我尝试了许多方法/解决方案,但似乎没有一种有效:

MDN 建议的方法

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
  return a.concat(b);
}, []);

带连接

data = [].concat.apply([], enc);

通过函数

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

但到目前为止没有任何乐趣,它一直按原样返回数组。任何人都可以指出我正确的方向并解释为什么会这样?

-编辑- 底线:我需要它返回一个常规的 Array 对象,比如未键入的起始对象。

【问题讨论】:

    标签: javascript arrays multidimensional-array flatten


    【解决方案1】:

    如果encUint8ClampedArrays 的Array,则此单行语句应该有效:

    var flattened = Uint8ClampedArray.from(enc.reduce((a, b) => [...a, ...b], []));
    

    这相当于:

    var flattened = Uint8ClampedArray.from(enc.reduce(function(a, b){
      return Array.from(a).concat(Array.from(b));
    }, []));
    

    回答您关于为什么reduce 不适合您的实际问题:

    [].concat(Uint8ClampedArray([1, 2, 3, 4]));
    

    不幸的是,它没有返回[1, 2, 3, 4],而是[Uint8ClampedArray[4]]concat 不适用于类型化数组。

    【讨论】:

    • 但这会将类型化数组转换为普通数组(在将其转换回类型化数组之前)。那么,使用类型化数组有什么意义呢?
    【解决方案2】:

    我会先计算总长度,然后使用setset的优势是

    如果源数组是类型化数组,这两个数组可以共享 相同的底层 ArrayBuffer;浏览器会智能复制 缓冲区的源范围到目标范围。

    function flatten(arrays, TypedArray) {
      var arr = new TypedArray(arrays.reduce((n, a) => n + a.length, 0));
      var i = 0;
      arrays.forEach(a => { arr.set(a,i); i += a.length; });
      return arr;
    }
    console.log(flatten(
      [new Uint8ClampedArray([1,2,3]), new Uint8ClampedArray([4,5,6])],
      Uint8ClampedArray
    ));

    另一种方法是使用 blob,如 proposed by guest271314。正确的方法是

    function flatten(arrays, TypedArray, callback) {
      var reader = new FileReader();
      reader.onload = () => {
        callback(new TypedArray(reader.result));
      };
      reader.readAsArrayBuffer(new Blob(arrays));
    }
    flatten(
      [new Uint8ClampedArray([1,2,3]), new Uint8ClampedArray([4,5,6])],
      Uint8ClampedArray,
      result => console.log(result)
    );

    【讨论】:

      【解决方案3】:

      查看 MDN,TypedArrays 并没有共享很多正常的 JS 数组函数。

      您可以从固定数组中收集值,然后像这样初始化一个新数组:

      var enc = [Uint8ClampedArray.of(1, 2), Uint8ClampedArray.of(4, 8), Uint8ClampedArray.of(16, 32)]
      
      var flattened = Uint8ClampedArray.from(enc.reduce(function(acc, uintc){
        Array.prototype.push.apply(acc, uintc)
        return acc;
      }, []));
      
      console.log(flattened); // [object Uint8ClampedArray]
      console.log(flattened.join(',')); // "1,2,4,8,16,32"
      

      【讨论】:

      • 这似乎可行,尽管对于 a 应该是什么有点令人困惑。如果换成enc,就可以了。
      • 我忘记复制我的测试数组,它被称为'a';
      • 但这会将类型化数组转换为普通数组(在将其转换回类型化数组之前)。那么,使用类型化数组有什么意义呢?
      • 它不会转换为普通数组,最终扁平化的数组确实是Uint8ClampedArray。只有中间结果(来自类型化数组的值)存储在普通数组中,然后将其重新应用于类型化数组。
      【解决方案4】:

      编辑、更新

      firefox,正如@Oriol 所指出的,每晚目前在FileReader() result 返回[[object Uint8ClampedArray],[object Uint8ClampedArray],[object Uint8ClampedArray]]

      一种使用spread elementrest elementfor..of的方法,它返回与铬相同的结果,铬使用Blob()FileReader()TextEncoder()TextDecoder()JSON.parse() 接近

      var enc = [new Uint8ClampedArray(900)
                  , new Uint8ClampedArray(900)
                 , new Uint8ClampedArray(900)];
      
      var res = [];
      for (let prop of enc) [...res] = [...res, ...prop];
      
      console.log(res);

      或者,更简洁,正如@Oriol 所建议的那样

      var res = [];
      var enc = [new Uint8ClampedArray(900), new Uint8ClampedArray(900)]; 
      for (let prop of enc) res.push(...prop);
      

      您可以使用Blob() 将参数连接成单个Blob 对象、FileReader()JSON.parse()

      var enc = [new Uint8ClampedArray(900)
                  , new Uint8ClampedArray(900)
                 , new Uint8ClampedArray(900)];
      
      var blob = new Blob([enc]);
      
      var reader = new FileReader();
      reader.onload = () => {
        console.log(JSON.parse("[" + reader.result + "]"))
      }
      reader.readAsText(blob);

      或者,使用TextEncoder()TextDecoder()JSON.parse()

      var enc = [new Uint8ClampedArray(900)
                  , new Uint8ClampedArray(900)
                 , new Uint8ClampedArray(900)];
      
      var encoder = new TextEncoder();
      var arr = encoder.encode(enc);
      var decoder = new TextDecoder();
      var res = JSON.parse("[" + decoder.decode(arr) + "]");
      console.log(res);

      【讨论】:

      • 是的,这是一个我很容易理解的解决方案,因为我之前一直在使用 Blob。
      • This doesn't work on FirefoxJSON.parse: unexpected character
      • @Oriol 你能描述一下“不起作用”吗? JSON.parse: unexpected character 在这两种方法中都没有收到错误。你可以创建一个 jsfiddle 或 plnkr 来演示吗?您也可以使用.split(/,/).map(Number)。意想不到的角色是什么?
      • 不确定 Firefox 是否正确,但 reader.result 是字符串 "[[object Uint8ClampedArray],[object Uint8ClampedArray],[object Uint8ClampedArray]]"decoder.decode(arr) 也一样
      • 更新有效,但您可以使用var enc = [new Uint8ClampedArray(900), new Uint8ClampedArray(900)]; for (let prop of enc) res.push(...prop);。顺便说一句,我更新了我的答案,显示了使用带有类型数组的 blob 的正确方法。
      猜你喜欢
      • 2014-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      相关资源
      最近更新 更多