我认为Array#slice
的速度应该至少与这两个选项之一相同,甚至更快。虽然这意味着需要暂时分配重复的内存,但是1M个数字只占用大约64MB的内存(假设JavaScript引擎已经能够在底层使用真正的数组),因此在释放原始的64MB之前,暂时保留原始的64MB以及要保留的32MB似乎相当便宜:
array = array.slice(500000)
这样做的好处是它不会强制JavaScript引擎在内部使用对象而不是数组。(您正在执行的其他操作可能会导致此问题,但是...)
您已经说过您正在使用浮点数,您可以考虑使用Float64Array
而不是未定义类型的数组。这限制了您可以执行的操作,但确保您不会得到未优化的数组。当您从数组中删除条目时,您可能会得到未优化的数组,其访问时间明显较慢,因为它们最终成为具有命名属性而不是偏移访问的对象。(一个好的JavaScript引擎将尽可能地保持它们的优化;使用类型化数组将有助于防止您破坏其优化。)
这个(匆忙编写且很可能有缺陷的)NodeJS测试表明,splice
比slice
慢60%至95%,而V8在类型化数组的情况下可以很好地保持数组的优化,因为结果与未定义类型的数组的结果几乎相同:
"use strict";
let sliceStats = createStats();
let sliceTypedStats = createStats();
let spliceStats = createStats();
for (let c = 0; c < 100; ++c) {
if (test(buildUntyped, sliceStats, testSlice).length != 500000) throw new Error("1");
if (test(buildTyped, sliceTypedStats, testSlice).length != 500000) throw new Error("2");
if (test(buildUntyped, spliceStats, testSplice).length != 500000) throw new Error("3");
console.log(c);
}
console.log("slice ", avg(sliceStats.sum, sliceStats.count));
console.log("sliceTyped", avg(sliceTypedStats.sum, sliceTypedStats.count));
console.log("splice ", avg(spliceStats.sum, spliceStats.count));
function avg(sum, count) {
return (sum / count).toFixed(3);
}
function createStats() {
return {
count: 0,
sum: 0
};
}
function buildUntyped() {
let a = [];
for (let n = 0; n < 1000000; ++n) {
a[n] = Math.random();
}
return a;
}
function buildTyped() {
let a = new Float64Array(1000000);
for (let n = 0; n < 1000000; ++n) {
a[n] = Math.random();
}
return a;
}
function test(build, stats, f) {
let a;
let ignore = 0;
let start = Date.now();
for (let i = 0; i < 10; ++i) {
let s = Date.now();
a = build();
ignore += Date.now() - s;
a = f(a);
}
stats.sum += Date.now() - start - ignore;
++stats.count;
return a;
}
function testSlice(a) {
return a.slice(500000);
}
function testSplice(a) {
a.splice(0, 500000);
return a;
}
splice
比slice
慢60%(在我的机器上进行1000次迭代的时间分别为16ms和10ms),因此这是一个实质性的改进。 - T.J. Crowder