2010-12-29 7 views
12

Estoy un poco confundido con Javascript Typed Arrays.Matrices mecanografiadas en Gecko 2: concatenación y expansión Float32Array

Lo que tengo son varios Float32Array s, que no tienen concat método. No sé cuántos son por adelantado, por cierto. me gustaría para concatenar todos ellos dentro de otro Float32Array, pero:

  • como he dicho antes, no existe un método de concatenación
  • si trato de escribir más allá de la longitud de la matriz, no se expande la matriz (aka esto no funcionará - Tenga en cuenta que event.frameBuffer y tampón son tanto Float32Array y que no sé cuál será la longitud final de mi memoria intermedia):

var length_now = buffer.length; 
for (var i = 0; i < event.frameBuffer.length; i += 1) { 
     buffer [length_now + i] = event.frameBuffer[i]; 
} 

T La única solución que encontré es copiar Float32Array en una matriz regular, eso definitivamente no es lo que quiero. ¿Cómo lo harías, Stackoverflowers?

Respuesta

19

Las matrices tipadas se basan en array buffers, que no se pueden cambiar de tamaño dinámicamente, por lo que no es posible escribir más allá del final de la matriz o usar push().

Una forma de lograr lo que quiere sería asignar un nuevo Float32Array, lo suficientemente grande como para contener ambas matrices, y realizar una copia optimizada:

function Float32Concat(first, second) 
{ 
    var firstLength = first.length, 
     result = new Float32Array(firstLength + second.length); 

    result.set(first); 
    result.set(second, firstLength); 

    return result; 
} 

Eso le permitirá escribir:

buffer = Float32Concat(buffer, event.frameBuffer); 
+0

Esto es realmente grande. Dos preguntas: ¿volver a crear de forma continua una nueva matriz tipada que no afectará las actuaciones? y ¿dónde encontraste documentación sobre el miembro de la función .set? No está en la página que vinculó. – janesconference

+0

@janesconference, bueno, no necesariamente afectará el rendimiento ya que 'set()' probablemente se implemente de forma nativa y, como tal, deslumbrantemente rápido con blits de memoria, pero tendrá un impacto en la memoria ya que no se puede extender una matriz de tipo existente . Dependiendo del tamaño de la matriz, si la memoria escasea, puede producirse una paliza y el rendimiento se degradará enormemente como resultado. –

+0

@ FrédéricHamidi: Hay otro problema que no es la implementación "nativa": supongamos que tiene n matrices con m elementos que desea concatenar. Su complejidad es entonces O (m^2), ya que copiará bloques de datos cada vez más grandes. La solución óptima se amortiza O (m). – user877329

2

O si usted está tratando de unirse a matrices N:

// one-liner to sum the values in an array 
function sum(a){ 
    return a.reduce(function(a,b){return a+b;},0); 
} 

// call this with an array of Uint8Array objects 
function bufjoin(bufs){ 
    var lens=bufs.map(function(a){return a.length;}); 
    var aout=new Uint8Array(sum(lens)); 
    for (var i=0;i<bufs.length;++i){ 
    var start=sum(lens.slice(0,i)); 
    aout.set(bufs[i],start); // copy bufs[i] to aout at start position 
    } 
    return aout; 
} 
0

he tenido el mismo problema, puede añadir el siguiente al prototipo

Float32Array.prototype.concat = function() { 
    var bytesPerIndex = 4, 
     buffers = Array.prototype.slice.call(arguments); 

    // add self 
    buffers.unshift(this); 

    buffers = buffers.map(function (item) { 
     if (item instanceof Float32Array) { 
      return item.buffer; 
     } else if (item instanceof ArrayBuffer) { 
      if (item.byteLength/bytesPerIndex % 1 !== 0) { 
       throw new Error('One of the ArrayBuffers is not from a Float32Array'); 
      } 
      return item; 
     } else { 
      throw new Error('You can only concat Float32Array, or ArrayBuffers'); 
     } 
    }); 

    var concatenatedByteLength = buffers 
     .map(function (a) {return a.byteLength;}) 
     .reduce(function (a,b) {return a + b;}, 0); 

    var concatenatedArray = new Float32Array(concatenatedByteLength/bytesPerIndex); 

    var offset = 0; 
    buffers.forEach(function (buffer, index) { 
     concatenatedArray.set(new Float32Array(buffer), offset); 
     offset += buffer.byteLength/bytesPerIndex; 
    }); 

    return concatenatedArray; 
}; 

ahora se puede hacer simplemente

var array1 = new Float32Array(10000000), 
    array2 = new Float32Array(10000000); 

var array3 = array1.concat(array2);