2010-12-29 24 views
12

Tôi hơi bối rối với Javascript Typed Arrays.Mảng đã nhập trong Gecko 2: Kết nối và mở rộng Float32Array

Tôi có một số Float32Array s, không có phương thức concat. Tôi không biết có bao nhiêu người ở trước, btw. Tôi muốn nối tất cả chúng bên trong một Float32Array, nhưng:

  • như tôi đã nói trước đây, không có phương pháp nối
  • nếu tôi cố gắng viết qua chiều dài mảng, mảng không được mở rộng (aka này sẽ không làm việc - xin lưu ý rằng event.frameBuffer và đệm đều Float32Array và rằng tôi không biết những gì chiều dài cuối cùng của bộ đệm của tôi sẽ được):

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

T ông chỉ giải pháp tôi tìm thấy là để sao chép Float32Array trong một mảng thường xuyên, đó chắc chắn không phải là những gì tôi muốn. Làm thế nào bạn sẽ làm, stackoverflowers?

Trả lời

19

Mảng đã nhập dựa trên array buffers, không thể thay đổi kích cỡ động, vì vậy việc viết qua phần cuối của mảng hoặc sử dụng push() là không thể.

Một cách để đạt được những gì bạn muốn sẽ được phân bổ một mới Float32Array, đủ lớn để chứa cả mảng, và thực hiện một bản sao tối ưu hóa:

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

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

    return result; 
} 

Điều đó sẽ cho phép bạn viết:

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

Đây là thực sự tuyệt vời. Hai câu hỏi: liên tục tái tạo một mảng được đánh máy mới sẽ không ảnh hưởng đến buổi biểu diễn? và bạn đã tìm tài liệu về thành viên hàm .set ở đâu? Nó không nằm trong trang bạn đã liên kết. – janesconference

+0

@janesconference, tốt, nó sẽ không nhất thiết ảnh hưởng đến hiệu suất vì 'set()' có thể được thực thi một cách tự nhiên và nhanh như chớp, nhưng nó sẽ ảnh hưởng đến bộ nhớ vì bạn không thể mở rộng mảng kiểu hiện có . Tùy thuộc vào kích thước mảng, nếu bộ nhớ trở nên khan hiếm, sự va đập có thể xảy ra và hiệu suất sẽ giảm đi rất nhiều. –

+0

@ FrédéricHamidi: Có một vấn đề khác so với việc triển khai "gốc": Giả sử rằng bạn có n mảng với các phần tử m mà bạn muốn ghép nối. Độ phức tạp của bạn sau đó là O (m^2), vì bạn sẽ sao chép các khối dữ liệu lớn hơn và lớn hơn. Giải pháp tối ưu được khấu hao O (m). – user877329

2

Hoặc nếu bạn đang cố gắng tham gia N mảng:

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

tôi đã cùng một vấn đề, bạn có thể thêm những điều sau đây để nguyên mẫu

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

bây giờ bạn có thể dễ dàng làm

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

var array3 = array1.concat(array2);