如何在 JavaScript 中合并 TypedArrays?

IT技术 javascript typed-arrays
2021-03-17 16:39:03

我想合并多个数组缓冲区来创建一个 Blob。但是,如您所知, TypedArray没有“推送”或有用的方法......

例如:

var a = new Int8Array( [ 1, 2, 3 ] );
var b = new Int8Array( [ 4, 5, 6 ] );

结果,我想得到[ 1, 2, 3, 4, 5, 6 ].

6个回答

使用set方法。但请注意,您现在需要两倍的内存!

var a = new Int8Array( [ 1, 2, 3 ] );
var b = new Int8Array( [ 4, 5, 6 ] );

var c = new Int8Array(a.length + b.length);
c.set(a);
c.set(b, a.length);

console.log(a);
console.log(b);
console.log(c);
谢谢您的回复。我能理解。我需要创建一个新的合并一个不是我。
2021-04-25 16:39:03
@yomotsu 是的,您需要创建一个新的。如果您了解 C,则 TypedArray 类似于使用malloc(无需使用free)。但没有什么像realloc.
2021-04-30 16:39:03
NPM 上有一个包(npmjs.com/package/concat-typed-array)。我花了一段时间,但我终于发现它的输出与你的匹配。codeandbox.io/s/... 令我失望的是,我需要在使用.toString().
2021-05-09 16:39:03
@Ryan 那是因为否则你正在比较不同的引用(它是一个新数组,一个指向内存位置的新指针)。要比较数组内容,您总是需要逐个元素地比较它们。[1] === [1]是假的。
2021-05-14 16:39:03

对于客户端 ~ok 解决方案:

const a = new Int8Array( [ 1, 2, 3 ] )
const b = new Int8Array( [ 4, 5, 6 ] )
const c = Int8Array.from([...a, ...b])
@Timmmm 它仅适用于函数调用的参数。When using spread syntax for function calls,...并且But beware: by using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit还它说argument limit of 65536. 我测试传播有两个65536长度Int8Arrays和它的作品。
2021-04-18 16:39:03
它与此相同,但具有更长的数组。阅读文档
2021-04-29 16:39:03
这将遇到长度限制。您不应该对无界数据使用扩展运算符。
2021-05-03 16:39:03
这种不太冗长的解决方案的唯一缺点是它创建了一个中间数组而不是类型化数组。无论如何,对于较短的阵列,这不会成为问题。
2021-05-08 16:39:03
@Timmmm 还测试了 2 个 16777216 长度的 Int8arrays 并且传播仍然可以使用它
2021-05-14 16:39:03

我总是使用这个功能:

function mergeTypedArrays(a, b) {
    // Checks for truthy values on both arrays
    if(!a && !b) throw 'Please specify valid arguments for parameters a and b.';  

    // Checks for truthy values or empty arrays on each argument
    // to avoid the unnecessary construction of a new array and
    // the type comparison
    if(!b || b.length === 0) return a;
    if(!a || a.length === 0) return b;

    // Make sure that both typed arrays are of the same type
    if(Object.prototype.toString.call(a) !== Object.prototype.toString.call(b))
        throw 'The types of the two arguments passed for parameters a and b do not match.';

    var c = new a.constructor(a.length + b.length);
    c.set(a);
    c.set(b, a.length);

    return c;
}

不检查 null 或类型的原始函数

function mergeTypedArraysUnsafe(a, b) {
    var c = new a.constructor(a.length + b.length);
    c.set(a);
    c.set(b, a.length);

    return c;
}
没有null检查,==而不是===,这基本上是 Prinzhorn 答案的重复,包装在一个函数中。
2021-04-30 16:39:03
同样,只是我喜欢使用的一些功能,我想也许其他人也可以使用它 - 可以自由地纠正您可能发现的任何错误。
2021-05-07 16:39:03
好吧,我从未在我的用例中看到需要进行严格比较或空检查,但如果它不会对性能产生负面影响,它会使功能更加充实。
2021-05-09 16:39:03
人们通常不会纠正答案代码中的错误。这取决于回答问题的人,因此是评论。
2021-05-10 16:39:03
是的!当然,扔字符串总是受欢迎的。我当然希望你成为我的同事。
2021-05-16 16:39:03

如果我有多个类型化数组

            arrays = [ typed_array1, typed_array2,..... typed_array100]

我想将所有 1 到 100 个子数组连接到单个“结果”中,这个函数对我有用。

  single_array = concat(arrays)


function concat(arrays) {
  // sum of individual array lengths
  let totalLength = arrays.reduce((acc, value) => acc + value.length, 0);

  if (!arrays.length) return null;

   let result = new Uint8Array(totalLength);

      // for each array - copy it over result
      // next array is copied right after the previous one
      let length = 0;
      for(let array of arrays) {
            result.set(array, length);
            length += array.length;
      }

      return result;
   }

作为一个单行,它将采用任意数量的数组(myArrays此处)和混合类型,只要结果类型全部采用(Int8Array此处):

let combined = Int8Array.from(Array.prototype.concat(...myArrays.map(a => Array.from(a))));