2010-12-29 15 views
12

Jestem nieco zdezorientowany z Javascript Typed Arrays.Wpisane tablice w Gecko 2: Float32Array konkatenacja i rozszerzenie

Co mam kilka Float32Array s, które nie mają concat metody. Nie wiem, ilu ich jest z góry, btw. chciałbym złączyć je wszystkie wewnątrz innego Float32Array, ale:

  • jak powiedziałem wcześniej, nie ma metody konkatenacji
  • jeśli staram się pisać przeszłość długości tablicy, tablica nie jest rozszerzona (aka to nie będzie działać - proszę pamiętać, że event.frameBuffer i bufor są zarówno Float32Array i że nie wiem, co ostateczna długość mojego bufora będzie):

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

T Jedyne rozwiązanie, jakie znalazłem, to skopiowanie Float32Array w regularnej tablicy, to zdecydowanie nie jest to, czego chcę. Jak byś zrobił, stackoverflowers?

Odpowiedz

19

Typowe tablice są oparte na numerze array buffers, którego nie można zmienić w sposób dynamiczny, więc zapisanie poza końcem tablicy lub użycie push() nie jest możliwe.

Jednym ze sposobów osiągnięcia tego, co chcesz byłoby przeznaczyć nowy Float32Array, wystarczająco duży, aby zawierać obie tablice i wykonywać zoptymalizowany kopię:

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

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

    return result; 
} 

który pozwoliłby Ci napisać:

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

To jest naprawdę wielki. Dwa pytania: ciągłe ponowne tworzenie nowej tablicy maszynowej nie wpłynie na wydajność? i gdzie znalazłeś dokumentację dotyczącą członka funkcji .set? Nie ma go na połączonej stronie. – janesconference

+0

@janesconference, cóż, niekoniecznie będzie to miało wpływ na wydajność, ponieważ 'set()' jest prawdopodobnie implementowane natywnie i, jako takie, jest oślepiająco szybkie w przypadku blits pamięci, ale będzie miało wpływ na pamięć, ponieważ nie można po prostu rozszerzyć istniejącej tablicy typów . W zależności od rozmiaru tablicy, jeśli pamięć przestaje być dostępna, może wystąpić dreszcz, a wydajność w rezultacie ogromnie się pogorszy. –

+0

@ FrédéricHamidi: Jest inny problem niż "natywna" implementacja: Załóżmy, że masz n tablic z m elementami, które chcesz łączyć. Twoja złożoność to O (m^2), ponieważ będziesz kopiować coraz większe bloki danych. Optymalnym rozwiązaniem jest amortyzowany O (m). – user877329

2

Albo jeśli próbujesz dołączyć N tablice:

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

miałem ten sam problem, Można dodać następujące prototypu

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; 
}; 

teraz po prostu można zrobić

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

var array3 = array1.concat(array2);