2009-09-19 102 views
3

我需要將FAST複製到另一個陣列的一部分,替換它的舊值。Javascript - 將陣列部分複製到另一個陣列的最快方法

  • 不需要範圍檢查。
  • 項目數複製:16384
  • 數組只包含整數

基準代碼: http://codebase.es/test/copytest.htm

這是我的方法:

var i = 0x4000>>5; // loops count 
    var j = 0x4000; // write start index 
    var k = 0x8000; // read start index 
    while (i--) {  // loop unrolling 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++];  
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    //8 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++];  
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    //16 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++];  
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    //24 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++];  
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    dst[j++]=src[k++]; dst[j++]=src[k++]; 
    //32 
    }  

可以這樣做快?

+3

輕微的性能增益是使用decremet預/預遞增,而不是遞減後/後遞增。 – Gumbo 2009-09-19 17:41:30

+0

Gumbo,你說得對。它快一點。如果你寫你的評論作爲答案,並沒有最好的解決方案,我會給你 – Peter 2009-09-19 18:01:53

+0

我知道這是很晚,但很好奇。爲什麼不只是'var dst = src.concat()'?我認爲這可能是克隆數組的最快方法。這不是深層複製。對於深度複製循環是唯一的方法。 – 2011-11-27 23:19:37

回答

2

你可以繼續展開循環中表現得輕微增長,但似乎這只是儘可能快,你」重新獲得它。作爲秋葵的評論指出,請嘗試使用預增量,而不是後加的:

var i = 0x4000>>5 + 1; // loops count 
var j = 0x4000 - 1; // write start index 
var k = 0x8000 - 1; // read start index 
while (--i) {  // loop unrolling 
    dst[++j]=src[++k]; dst[++j]=src[++k]; 
    dst[++j]=src[++k]; dst[++j]=src[++k];  
    dst[++j]=src[++k]; dst[++j]=src[++k]; 
    dst[++j]=src[++k]; dst[++j]=src[++k]; 
    //8 
    ... 
+0

爲什麼不爲'我 - '呢? – Gumbo 2009-09-19 17:54:20

+0

對,錯過了 – 2009-09-19 18:07:21

3

林不知道你的方法比這個速度更快:

var i = 0x4000;  // loops count 
var j = 0x4000; // write start index 
var k = 0x8000; // read start index 
while (i--) {  // loop unrolling 
    dst[j++]=src[k++]; 
} 
+0

它是(在鉻,FF3.5和Opera測試) 看看: http://codebase.es/test/copytest.htm – Peter 2009-09-19 17:23:07

1

我會考慮切片方法:

var dst = src.slice(start,end) 

性能取決於JavaScript引擎的實現,但想必所有的瀏覽器在他們的平臺上儘可能高效地實施。

查看更多here

+0

他要求替換另一個數組的內容,而不是形成一個新的一。 – 2009-09-19 17:09:43

+0

@cemkalyoncu:然後做'切片'和'拼接'。 – Gumbo 2009-09-19 17:18:39

+4

「切片和拼接」聽起來像電視直接響應產品。 「厭倦了寫入笨拙的循環?嘗試新的Slice和Splice!它切片,它拼接,它將痛苦排除在陣列處理之外,現在訂購只需19.95美元!」 – 2009-09-19 17:35:08

0

另一種價值標杆,可以建立一個全新的dst陣列只有幾個強大的原語,而不是執行的循環,即:

dst = dst.slice(0, writestart).concat(
    src.slice(readstart, readstart+count), 
    dst.slice(writestart+count)); 

這種方法如何表現循環的比較無疑會隨着數組長度和數量以及底層JavaScript引擎的不同而變化 - 猜測效率不高,這就是爲什麼我建議使用基準測試的原因;-)。

+0

這大約慢了10倍 – Peter 2009-09-19 17:34:18

+0

一些內部函數很可能用C++編寫,其工作速度慢於解釋一堆線,這很奇怪。順便說一句,我測試了相同的代碼在C中產生6-14毫秒的複製時間(1000 x 0x4000元素) – 2009-09-19 17:43:25

+1

現代瀏覽器將JavaScript編譯成機器代碼。例如Chrome的V8和FF的TraceMonkey。 – Peter 2009-09-19 17:45:29

0

嘗試使用內置的方法slicesplice組合:

Array.prototype.splice.apply(dst, [j, i].concat(src.slice(k, k+i))); 
+0

對不起。你的解決方案慢了大約50倍。 – Peter 2009-09-19 17:55:39

+0

如果您希望它表現良好,請不要使用它。 – Derrick 2011-04-18 11:42:29

0

您可以通過

function compileCopy(count, di, si) { 
    var sb = new Array(count); 
    di += count, si += count; 
    while(count--) sb[count] = --di + ']=src[' + --si; 
    return new Function('dst[' + sb.join('];dst[') + '];'); 
} 

var copy = compileCopy(0x4000, 0x4000, 0x8000); 

在Opera創建一個完全展開的版本,例如,它會稍微快一些比循環版本。在FF ...不是(甚至有可能是某處的某個bug)。

+0

但是起始索引被硬編碼到「編譯」函數中。對於每個複製調用,您需要再次「編譯」它。 – Peter 2009-09-19 19:11:56

+0

您的基準代碼也有硬編碼索引 – Christoph 2009-09-19 19:19:35

+0

但它們可能是功能參數而不會損失性能。 – Peter 2009-09-19 19:52:59

1

對不起,一年過去了,但..這是最快的FF:

function copy4() { 
    var i = 0x4000; // loops count 
    var j = 0x4000; // write start index 
    var k = 0x8000; // read start index 

    var args = src.slice(k, k+i); 
    args.unshift(i); 
    args.unshift(j); 
    Array.prototype.splice.apply(dst,args); 
} 
相關問題