2010-12-29 5 views
12

Sono un po 'confuso con Javascript Typed Arrays.Array tipizzati in Gecko 2: Concatenazione ed espansione Float32Array

Quello che ho sono diversi Float32Array s, che non hanno alcuna concat metodo. Non so quanti sono in anticipo, btw. Vorrei concatenare tutti all'interno di un altro Float32Array, ma:

  • come detto prima, non esiste un metodo di concatenazione
  • se provo a scrivere oltre la lunghezza della matrice, la matrice non viene espansa (aka questo non funzionerà - si ricorda che event.frameBuffer e tampone sono entrambi Float32Array e che non so quale sarà la lunghezza finale della mia buffer):

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

T l'unica soluzione che ho trovato è copiare il Float32Array in un array regolare, che non è sicuramente quello che voglio. Come faresti, stackoverflowers?

risposta

19

Gli array tipizzati si basano su array buffers, che non può essere ridimensionato in modo dinamico, quindi non è possibile scrivere oltre la fine dell'array o utilizzare push().

Un modo per ottenere ciò che si desidera potrebbe essere quella di allocare un nuovo Float32Array, sufficientemente grande da contenere entrambi gli array, ed eseguire una copia ottimizzata:

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

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

    return result; 
} 

che permetterebbe di scrivere:

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

Questo è davvero grande. Due domande: ricreare continuamente un nuovo array tipizzato non avrà impatto sulle prestazioni? e dove hai trovato la documentazione sul membro della funzione .set? Non è nella pagina che hai collegato. – janesconference

+0

@janesconference, beh, non influenzerà necessariamente le prestazioni poiché 'set()' è probabilmente implementato in modo nativo e, come tale, accecantemente veloce con blit di memoria, ma avrà un impatto sulla memoria poiché non si può semplicemente estendere un array di tipi esistente . A seconda delle dimensioni dell'array, se la memoria scarseggia, si potrebbe verificare un thrashing e di conseguenza le prestazioni si ridurranno enormemente. –

+0

@ FrédéricHamidi: Esiste un altro problema rispetto all'implementazione "nativa": si supponga di avere n array con m elementi che si desidera concatenare. La complessità è quindi O (m^2), poiché copi blocchi di dati sempre più grandi. La soluzione ottimale è ammortizzata O (m). – user877329

2

Oppure, se si sta cercando di unirsi N matrici:

// 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

ho avuto lo stesso problema, è può aggiungere la seguente 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; 
}; 

ora si può semplicemente fare

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

var array3 = array1.concat(array2);