サイズがN
(ここでN > 0
)の配列があるとすると、O(N + 1)ステップを必要としない、配列の前に付加するより効率的な方法はありますか?
コードでは、本質的に、私が現在やっていることは
function prependArray(value, oldArray) {
var newArray = new Array(value);
for(var i = 0; i < oldArray.length; ++i) {
newArray.Push(oldArray[i]);
}
return newArray;
}
Big-Oの観点からはもっと効率的かどうかはわかりませんが、確かにunshift
メソッドを使用する方がより簡潔です。
var a = [1, 2, 3, 4];
a.unshift(0);
a; // => [0, 1, 2, 3, 4]
[編集]
これは jsPerfベンチマーク 異なるbig-Oパフォーマンスに関係なく、少なくとも2つのブラウザでunshift
がかなり高速であることを示していますifインプレースで配列を変更すれば大丈夫です。元の配列を実際に変更できない場合は、以下のスニペットのようにします。これは、ソリューションよりもそれほど速くはないようです。
a.slice().unshift(0); // Use "slice" to avoid mutating "a".
[編集2]
完全を期すために、OPの例のprependArray(...)
の代わりに次の関数を使って、Arrayのunshift(...)
メソッドを利用することができます。
function prepend(value, array) {
var newArray = array.slice();
newArray.unshift(value);
return newArray;
}
var x = [1, 2, 3];
var y = prepend(0, x);
y; // => [0, 1, 2, 3];
x; // => [1, 2, 3];
ある配列を別の配列の前に追加する場合は、concat
を使用するほうが効率的です。そう:
var newArray = values.concat(oldArray);
しかし、これはやはりoldArrayのサイズのO(N)になります。それでも、oldArrayを手動で繰り返すよりも効率的です。また、詳細によっては、多くの値を先頭に追加する場合は、個々の先頭に値を追加するのではなく、最初に値を配列に配置してから最後に連結することをお勧めします。
配列は固定位置の最初の要素を使用して連続したメモリに格納されるため、oldArrayのサイズでO(N)よりも優れた方法はありません。最初の要素の前に挿入したい場合は、他のすべての要素を移動する必要があります。これを回避する方法が必要な場合は、@ GWWの指示に従ってリンクリスト、または別のデータ構造を使用してください。
ES6では、元の要素の前に新しい要素を挿入して新しい配列を作成するために スプレッド演算子 を使用できます。
// Prepend a single item.
const a = [1, 2, 3];
console.log([0, ...a]);
// Prepend an array.
const a = [2, 3];
const b = [0, 1];
console.log([...b, ...a]);
私はこの答えに、もっと記憶に残る簡潔な構文を提示することを意図しました。いくつかのベンチマークによれば( この他の答え を参照)、この構文はかなり遅いということに注意すべきです。これらの操作の多くをループで行わない限り、これはおそらく問題にはなりません。
もしあなたが配列(a1に配列a2)を追加したいのであれば、次のようにすることができます。
var a1 = [1, 2];
var a2 = [3, 4];
Array.prototype.unshift.apply(a1, a2);
console.log(a1);
// => [3, 4, 1, 2]
古い配列を保存し、古い配列をスライスし、新しい値をスライスの先頭にシフトする必要がある場合。
var oldA=[4,5,6];
newA=oldA.slice(0);
newA.unshift(1,2,3)
oldA+'\n'+newA
/* returned value:
4,5,6
1,2,3,4,5,6
*/
特別な方法があります。
a.unshift(value);
しかし、配列の前にいくつかの要素を追加したいのであれば、そのような方法を使うほうが速いでしょう。
var a = [1, 2, 3],
b = [4, 5];
function prependArray(a, b) {
var args = b;
args.unshift(0);
args.unshift(0);
Array.prototype.splice.apply(a, args);
}
prependArray(a, b);
console.log(a); // -> [4, 5, 1, 2, 3]
私は前置きのさまざまな方法のいくつかの新鮮なテストがあります。小さなアレイ(<1000 elems)の場合、リーダーはプッシュ方式のサイクル結合用です。巨大な配列では、Unshiftメソッドがリーダーになります。
しかし、この状況はChromeブラウザの場合にのみ発生します。 Firefoxでは、unshiftは最適化が非常に良く、どの場合でも高速です。
ES6スプレッドはすべてのブラウザで100倍以上遅くなります。
インプレースインプレフィックスの例:
var A = [7,8,9]
var B = [1,2,3]
A.unshift(...B)
console.log(A) // [1,2,3,7,8,9]
unshift
を呼び出すと、新しい配列の長さだけが返されます。したがって、最初に要素を追加して新しい配列を返すには、次のようにしました。
let newVal = 'someValue';
let array = ['hello', 'world'];
[ newVal ].concat(array);
あるいは単純にスプレッド演算子を使って:
[ newVal, ...array ]
このように、元の配列はそのまま残ります。