2009-09-19 2 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

+0

Гумбо, ты прав. Это немного быстрее.Если вы напишете свой комментарий как ответ, и нет лучшего решения, я дам его вам – Peter

+0

Я знаю, что это очень поздно, но было любопытно. Почему не просто 'var dst = src.concat()'? Я думаю, что это, вероятно, самый быстрый способ клонирования массива. Однако это не глубокая копия. Для глубокого копирования цикл - единственный способ пойти. –

ответ

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

Почему не для 'i -' тоже? – Gumbo

+0

Справа, пропущено это –

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

1

Я хотел бы рассмотреть метод среза:

var dst = src.slice(start,end) 

Производительность зависит от реализации JavaScript двигателя, но предположительно все браузеры как можно более эффективны на своей платформе.

Подробнее here

+0

Он просит заменить содержимое другого массива, а не сформировать новый один. –

+0

@cemkalyoncu: Затем сделайте 'slice' и' splice'. – Gumbo

+4

«Нарезка и сращивание» звучит как продукт прямого ответа на телевизор. «Устали писать неуклюжими для циклов? Попробуйте новый Slice и Splice! Он срезает, он сращивается, он берет боль из обработки массивов. Закажите сейчас всего за $ 19,95!» –

0

Альтернатива стоит бенчмаркинг может строить совершенно новый dst массива с помощью всего несколько мощных примитивов вместо выполнения цикла, то есть:

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

Как производительность этого подхода сравнивается с циклом, без сомнения, будет варьироваться в зависимости от длины и количества массивов, а также с базовым механизмом Javascript - угадание не будет очень продуктивным, поэтому я предлагаю вместо этого бенчмаркинг ;-).

+0

Это примерно в 10 раз медленнее – Peter

+0

Некоторые внутренние функции, которые, скорее всего, написаны на C++, работают медленнее, чем интерпретация пучка строк, странно. BTW Я тестировал один и тот же код в C в результате 6-14 мс времени копирования (1000 x 0x4000 элементов) –

+1

современные браузеры компилируют javascript в машинный код. Например, Chrome V8 и Fce TraceMonkey. – Peter

0

Попробуйте сочетание с методом построения в slice и splice:

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

Извините. Ваше решение примерно в 50 раз медленнее. – Peter

+0

Нет, если вы хотите, чтобы он хорошо работал. – Derrick

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 ... нет (там может быть какая-то ошибка).

+0

Но начальные индексы жестко закодированы в «скомпилированную» функцию. Для каждого вызова копии вам нужно будет «скомпилировать» его снова. – Peter

+0

ваш контрольный код также имеет индексы с жестким кодом – Christoph

+0

, но они могут быть функциональными параметрами без потери производительности. – Peter

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); 
} 
Смежные вопросы