JavaScriptで任意の長さのゼロで満たされた配列を作成する最も効率的な方法は何ですか?
let i = 0; Array.from(Array(10), ()=>i++);
JavaScriptで任意の長さのゼロで満たされた配列を作成する最も効率的な方法は何ですか?
let i = 0; Array.from(Array(10), ()=>i++);
回答:
ES6が導入しArray.prototype.fill
ます。次のように使用できます。
new Array(len).fill(0);
高速かどうかはわかりませんが、短くて自己記述的なので気に入っています。
IEにはまだありません(互換性を確認してください)が、利用可能なポリフィルがあります。
new Array(len)
痛いほど遅いです。(arr = []).length = len; arr.fill(0);
どこでも見られる最速のソリューションについて...または少なくとも
arr = Array(n)
と(arr = []).length = n
仕様に従って同じように動作します。実装によってはより高速になる場合もありますが、大きな違いはないと思います。
(arr = []).length = 1000;
をarr = new Array(1000);
速度に対して使用して、ChromeとFFの両方でテストしnew
ます。速度が非常に遅くなります。さて、配列の長さが小さい場合.. <50かそこらについて言ってください...するとnew Array()
、パフォーマンスが向上するようです。しかし..
arr.fill(0)
... テストに2行目を追加すると... ...すべてが多少変更されます。これで、new Array()
配列のサイズが100000を超える場合を除いて、ほとんどの場合で使用が速くなります。その後、速度の増加を再び確認できます。しかし、実際にゼロを事前に入力する必要がなく、空の配列の標準ファリシーを使用できる場合。そう(arr = []).length = x
すれば、ほとんどの場合、テストケースで非常に速くなります。
new Array(5).forEach(val => console.log('hi'));
vsを試してくださいnew Array(5).fill(undefined).forEach(val => console.log('hi'));
。
これは古いスレッドですが、2セント追加したいと思いました。これがどれほど遅い/速いかわかりませんが、それは速いワンライナーです。これが私がすることです:
番号を事前に入力したい場合:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
文字列を事前に入力したい場合:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
他の回答が示唆しています:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
しかし、「0」(文字列内のゼロ)ではなく0(数値)が必要な場合は、次のようにすることができます。
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
か?(new Array(5))。map(...)を単純に実行すると、仕様が示すように機能しません
new
あなたがないとき)Array(5)
:あなたはちょっと、このようになっていることをオブジェクト作成している{ length: 5, __proto__: Array.prototype }
試みを- console.dir( Array(5) )
。それはどんな性質を持っていないことに注意してください0
、1
、2
、などしかし、あなたapply
がたことをArray
コンストラクタ、それは言ってようなものですArray(undefined, undefined, undefined, undefined, undefined)
。そして、あなたはちょっとのようなオブジェクトを取得します{ length: 5, 0: undefined, 1: undefined...}
。map
プロパティ0
、1
などで機能するため、例は機能しませんが、使用するapply
と機能します。
.apply
は、実際にはにしたいものですthis
。これらの目的にとってthis
は問題ではありません-私たちは本当に「機能」を広げるパラメータにのみ関心.apply
があるので、どんな値でもかまいません。私は次のようにnull
それの安いので、あなたはおそらく使用したくない{}
か、[]
あなたが理由もなくオブジェクトをインスタンス化すると思いますので、。
ES6を使用してこれを行う別の方法を次に示します。
> Array.from(Array(3), () => 0)
< [0, 0, 0]
これは、map関数をの2番目のパラメータとして渡すことで機能しますArray.from
。
上記の例では、最初のパラメーターが値で満たされた3つの位置の配列を割り当てundefined
、ラムダ関数がそれぞれの位置を値にマップします0
。
Array(len).fill(0)
短くなって、あなたが最初のいくつかの計算を行うことにより、配列を埋めるために必要がある場合、それは動作しません(私は質問がそれを要求しませんでしたが、多くの人がこれを見て、ここで終わる知っています)。
たとえば、10個の乱数を持つ配列が必要な場合:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
同等のものよりも簡潔(かつエレガント)です。
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
このメソッドは、コールバックで提供されるインデックスパラメータを利用することにより、数列を生成するためにも使用できます。
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
repeat()
この答えはかなり注目を集めているので、このクールなトリックも見せたかった。私の主な回答ほど有用ではありませんが、まだあまり知られていませんが、非常に有用なString repeat()
メソッドを紹介します。ここにトリックがあります:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
かっこいい?repeat()
は、元の文字列を特定の回数繰り返した文字列を作成するのに非常に便利な方法です。その後split()
、配列を作成し、map()
必要な値に移動します。段階的に分解する:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
トリックは本番では絶対に必要ではありませんが、Array.from()
完全に問題ありません:-)
最速のソリューション
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
最短の(便利な)ソリューション(小さなアレイでは3倍遅く、大きなアレイではわずかに遅くなります(Firefoxでは最も遅くなります))
Array(n).fill(0)
今日2020.06.09私は、ブラウザーChrome 83.0、Firefox 77.0、Safari 13.1のmacOS High Sierra 10.13.6でテストを実行しています。選択したソリューションを2つのテストケースでテストします
new Array(n)+for
(N)に基づくソリューションは、小さなアレイと大きなアレイ(Chromeを除くが、それでも非常に高速)で最も高速なソリューションであり、高速なクロスブラウザソリューションとして推奨されますnew Float32Array(n)
(I)に基づくソリューションは一般的な配列を返さないため(たとえば、呼び出すことができませんpush(..)
)、その結果を他のソリューションと比較しません。ただし、このソリューションは、すべてのブラウザーの大きな配列の他のソリューションよりも約10〜20倍高速です。for
(L、M、N、O)に基づくソリューションは、小さなアレイに対して高速ですfill
(B、C)に基づくソリューションは、ChromeとSafariでは高速ですが、Firefoxでは大きなアレイの場合、驚くほど低速です。小さなアレイでは中速ですArray.apply
(P)に基づくソリューションは、大きな配列に対してエラーをスローします
以下のコードは、測定で使用されるソリューションを示しています
Chromeの結果の例
let a=[]; for(i=n;i--;) a.push(0);
しかし、それは4倍遅いですfill(0)
-したがって、私はそのケースの画像魔女を更新しません。
すでに述べたES 6のfillメソッドはこれをうまく処理します。最近のほとんどのデスクトップブラウザーは、現在のところ必要なArrayプロトタイプメソッド(Chromium、FF、Edge、およびSafari)を既にサポートしています[ 1 ]。MDNで詳細を調べることができます。簡単な使用例は
a = new Array(10).fill(0);
現在のブラウザのサポートを考えると、読者が最新のデスクトップブラウザを使用していることが確実でない限り、これを使用するように注意する必要があります。
a = Array(10).fill(null).map(() => { return []; });
a = Array(10).fill(0).map( _ => [] );
2013年8月に追加され、2015年2月に更新されたメモ:2009年からの以下の回答は、JavaScriptのジェネリックArray
型に関連しています。など、ES2015で定義された新しい型付き配列(および現在多くのブラウザーで利用可能)とは関係ありませんInt32Array
。ES2015は、配列と型付き配列のfill
両方にメソッドを追加することにも注意してください。これは、これらを埋める最も効率的な方法と思われます...
また、一部の実装では、配列の作成方法に大きな違いが生じる可能性があります。特にChromeのV8エンジンは、可能であれば、非常に効率的な連続メモリ配列を使用しようとし、必要な場合にのみオブジェクトベースの配列にシフトします。
ほとんどの言語では、次のように、事前に割り当てられてからゼロで埋められます。
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
ただし、JavaScript配列は実際には配列ではなく、他のすべてのJavaScriptオブジェクトと同じようにキー/値マップであるため、実行する「事前割り当て」はありません(長さを設定しても、埋めるために多くのスロットが割り当てられることはありません)。実装がキーの処理を最適化している可能性がある場合に、キーを逆順で追加しても、ゼロまでカウントダウンするメリット(ループでの比較を高速化するため)を上回らないと考える理由はありますか?理論上の配列に関連して、通常は順番に実行します。
実際、Matthew Crumleyは、Firefoxでのカウントダウンはカウントアップよりも著しく遅いことを指摘しました。その結果、私は確認できます。それはその配列部分です(0にループダウンすることは、varの制限にループアップするよりも速いです)。要素を配列に逆の順序で追加することは、Firefoxでは遅い操作です。実際、結果はJavaScriptの実装によってかなり異なります(これは驚くべきことではありません)。以下は、ブラウザー実装の迅速でダーティなテストページ(下)です(非常にダーティで、テスト中に生成されないため、最小限のフィードバックを提供し、スクリプトの時間制限に違反します)。テスト間でリフレッシュすることをお勧めします。FF(少なくとも)を繰り返さないと、テストが遅くなります。
Array#concatを使用するかなり複雑なバージョンは、FFでの単純な初期化よりも、1,000〜2,000の要素配列のどこかで高速です。ただし、ChromeのV8エンジンでは、常にinitが優先されます...
これがテストページです(ライブコピー):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
font-weight: bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
'downpre': {
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
'downpost': {
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
'up': {
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
'downandup': {
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
'concat': {
total: 0,
desc: "Concat",
func: makeWithConcat
}
};
document.observe('dom:loaded', function() {
var markup, defname;
markup = "";
for (defname in testdefs) {
markup +=
"<div><input type='checkbox' id='chk_" + defname + "' checked>" +
"<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
}
$('checkboxes').update(markup);
$('btnTest').observe('click', btnTestClick);
});
function epoch() {
return (new Date()).getTime();
}
function btnTestClick() {
// Clear log
$('log').update('Testing...');
// Show running
$('btnTest').disabled = true;
// Run after a pause while the browser updates display
btnTestClickPart2.defer();
}
function btnTestClickPart2() {
try {
runTests();
}
catch (e) {
log("Exception: " + e);
}
// Re-enable the button; we don't yheidl
$('btnTest').disabled = false;
}
function runTests() {
var start, time, counter, length, defname, def, results, a, invalid, lowest, s;
// Get loops and length
s = $F('txtLoops');
runcount = parseInt(s);
if (isNaN(runcount) || runcount <= 0) {
log("Invalid loops value '" + s + "'");
return;
}
s = $F('txtLength');
length = parseInt(s);
if (isNaN(length) || length <= 0) {
log("Invalid length value '" + s + "'");
return;
}
// Clear log
$('log').update('');
// Do it
for (counter = 0; counter <= runcount; ++counter) {
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
start = epoch();
a = def.func(length);
time = epoch() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
invalid = validateResult(a, length);
if (invalid) {
log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
return;
}
}
else {
// Count this one
log("#" + counter + ": " + def.desc + ": " + time + "ms");
def.total += time;
}
}
}
}
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
def.avg = def.total / runcount;
if (typeof lowest != 'number' || lowest > def.avg) {
lowest = def.avg;
}
}
}
results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runcount +
"</p>";
for (defname in testdefs) {
def = testdefs[defname];
if ($('chk_' + defname).checked) {
results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
}
}
results += "<hr>";
$('log').insert({top: results});
}
function validateResult(a, length) {
var n;
if (a.length != length) {
return "Length is wrong";
}
for (n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
var a;
a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
var a;
a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
var a, i;
a = new Array(len);
for (i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
var a, i;
a = new Array(len);
i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
var a, rem, currlen;
if (len == 0) {
return [];
}
a = [0];
currlen = 1;
while (currlen < len) {
rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
}
else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
$('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>
デフォルトUint8Array
ではUint16Array
、Uint32Array
クラスは値としてゼロを保持するため、複雑な塗りつぶし手法は必要ありません。次のようにしてください:
var ary = new Uint8Array(10);
配列のすべての要素はary
デフォルトでゼロになります。
Array.isArray(ary)
ですfalse
。長さも読み取り専用なので、次のように新しいアイテムをプッシュすることはできませんary.push
0
デフォルト値のままにします。
Array.from(new Uint8Array(10))
、通常の配列を提供します。
Array(n).fill(0)
本当に必要なものがJS配列である場合、それはChrome の約5倍遅いことを示しています。TypedArrayを使用できる場合.fill(0)
、特にデフォルトの初期化子値を使用できる場合は、これはよりもはるかに高速です0
。C ++のように、fill-valueとlengthを取るコンストラクタはないようですstd::vector
。ゼロ以外の値の場合は、ゼロに設定されたTypedArrayを作成してそれを埋める必要があります。:/
ES6を使用する場合、次のようにArray.from()を使用できます。
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
同じ結果になります
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
なぜなら
Array.from({ length: 3 })
//[undefined, undefined, undefined]
function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
注while
通常よりも効率的であるfor-in
、forEach
など
i
ローカル変数は無関係ではありませんか? length
値で渡されるため、直接デクリメントできるはずです。
arr[i] = value
)に値を割り当てるのは非常に遅いです。最初から最後までループしてを使用する方がはるかに高速arr.push(value)
です。私はあなたの方法を好むので、それは迷惑です。
オブジェクト表記の使用
var x = [];
ゼロ埋め?お気に入り...
var x = [0,0,0,0,0,0];
「未定義」でいっぱい...
var x = new Array(7);
ゼロ付きのobj表記
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
補足として、Arrayのプロトタイプを変更すると、両方とも
var x = new Array();
そして
var y = [];
プロトタイプが変更されます
とにかく、私はこの操作の効率や速度に過度に懸念することはありません。ゼロを含む任意の長さの配列をインスタンス化するよりもはるかに無駄でコストのかかることは他にもたくさんあります。
null
この配列にs はありませんvar x = new Array(7);
new Array(7)
「未定義で満たされた」配列は作成しません。これは、作成し、空の長さ7と配列
(new Array(10)).fill(0)
。
IE 6/7/8、Firefox 3.5、Chrome、Operaで、事前割り当て/事前割り当てなし、カウントアップ/ダウン、for / whileループのすべての組み合わせをテストしました。
以下の関数は、Firefox、Chrome、IE8で一貫して最速または非常に近く、OperaとIE 6で最速よりもそれほど遅くはありませんでした。whileループのバージョンがわずかに速いブラウザをいくつか見つけたので、参考のために含めます。
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
または
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
宣言をforループの最初の部分にコンマで区切って実際にスローすることもできます。
length
すでに与えられた値に設定され、それが常に変化しないようにします。私のマシンで、100万長のゼロの配列を40ミリ秒から8ミリ秒に変更しました。
for (i = 0, array = []; i < length; ++i) array[i] = val;
..ブロックが少ない?...とにかく、... array.length
新しい配列のを長さに設定すると、FFでさらに10%〜15%の速度増加が見られる... Chromeでは、速度が2倍になるようです-> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(for
ループのままにしておくと、まだ高速でしたが... initが不要になったため、while
このバージョンでは高速であると思われます)
コードの実行中にさまざまな長さの多くのゼロで満たされた配列を作成する必要がある場合、これを達成するために見つけた最も速い方法は、このトピックで説明されている方法の1つを使用して、ゼロの長さの配列を一度作成することです決して超えられないことがわかっていて、必要に応じてその配列をスライスします。
たとえば、(上記で選択した回答の関数を使用して配列を初期化する)、長さがmaxLengthのゼロで満たされた配列を、ゼロ配列を必要とするコードから見える変数として作成します。
var zero = newFilledArray(maxLength, 0);
ここで、必要な長さのゼロで満たされた配列が必要になるたびに、この配列をスライスしますrequiredLength < maxLength:
zero.slice(0, requiredLength);
私はコードの実行中に何千回もゼロで満たされた配列を作成していましたが、これによりプロセスが大幅にスピードアップしました。
私は反対しません:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
Zertoshによって提案されましたが、新しいES6配列拡張では、メソッドを使用してこれをネイティブに実行できますfill
。IEエッジ、Chrome、FFでサポートされていますが、互換性の表を確認してください
new Array(3).fill(0)
あなたに与えるでしょう[0, 0, 0]
。new Array(5).fill('abc')
(オブジェクトや他の配列でも)のような任意の値で配列を埋めることができます。
その上で、fillを使用して以前の配列を変更できます。
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
それはあなたに与える: [1, 2, 3, 9, 9, 6]
私が通常行う方法(そして驚くほど高速です)はを使用していUint8Array
ます。たとえば、1M要素のゼロで満たされたベクトルを作成します。
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
私はLinuxユーザーで、いつも働いてきましたが、かつてMacを使用している友人がいくつかのゼロでない要素を持っていました。私は彼のマシンが故障していると思ったが、それでも私たちがそれを修正するために見つけた最も安全な方法はここにある:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
編集済み
Chrome 25.0.1364.160
Firefox 20.0
最も重要なテスト(少なくとも私にとっては)がありません:Node.jsです。Chromeのベンチマークに近いと思います。
_.range(0, length, 0)
と思います。Lodashには最終値が含まれていません
ECMAScript2016の時点で、大きな配列には明確な選択肢が1つあります。
この回答は引き続きGoogle検索のトップ近くに表示されるため、2017年の回答を次に示します。
これは、この質問でこれまでに提案された多くを含む、数十の人気のあるメソッドを含む現在のjsbenchです。より良い方法を見つけたら、追加、フォーク、共有してください。
任意の長さのゼロで満たされた配列を作成するための真に最も効率的な方法はないことに注意したい。速度、または明確さと保守性を最適化できます。どちらも、プロジェクトのニーズに応じて、より効率的な選択肢と見なすことができます。
速度を最適化する場合、次のことを行います。リテラル構文を使用して配列を作成します。長さを設定し、反復変数を初期化し、whileループを使用して配列を反復処理します。ここに例があります。
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
別の可能な実装は次のとおりです。
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
ただし、この2番目の埋め込みはあまり明確ではなく、配列変数のブロックスコープを維持することができないため、実際には使用しないことを強くお勧めします。
これらは、forループを埋めるよりも大幅に高速で、標準の方法よりも約90%高速です。
const arr = Array(n).fill(0);
しかし、この塗りつぶし方法は、明快さ、簡潔さ、保守性のため、小さい配列の場合でも依然として最も効率的な選択肢です。数千以上の長さの配列を多数作成しない限り、パフォーマンスの違いはおそらくあなたを殺しません。
他のいくつかの重要な注意事項。ほとんどのスタイルガイドではvar
、ES6以降を使用する場合、特別な理由がない限り使用しないことを推奨しています。const
再定義されない変数と再定義される変数に使用しますlet
。MDNとAirbnbのスタイルガイドは、ベストプラクティスの詳細については、行くには絶好の場所です。質問は構文に関するものではありませんでしたが、JSの初心者がこれらの新旧の答えの範囲を検索するときに、これらの新しい標準について知っていることが重要です。
まったく新しいアレイを作成するには
new Array(arrayLength).fill(0);
既存の配列の最後にいくつかの値を追加するには
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
回答にこのメソッドが表示されなかったので、ここにあります:
"0".repeat( 200 ).split("").map( parseFloat )
結果として、長さ200のゼロ値配列が得られます。
[ 0, 0, 0, 0, ... 0 ]
このコードのパフォーマンスについてはわかりませんが、比較的小さな配列に使用しても問題にはなりません。
const arr = Array.from({ length: 10 }).fill(0)
このconcat
バージョンは、Chromeでのテストではるかに高速です(2013-03-21)。10,000,000要素の場合は約200ミリ秒、ストレート初期化の場合は675ミリ秒。
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
おまけ:配列を文字列で埋めたい場合、これを行うには簡潔な方法です(それほど高速ではconcat
ありません)。
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
私はTJ Crowderによるすばらしい答えを試していて、彼のChromeでのテストのどれよりも優れているconcatソリューションに基づく再帰的なマージを思いつきました(私は他のブラウザーをテストしませんでした)。
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
でメソッドを呼び出しますmakeRec(29)
。
ECMAScript 6(Harmony)の提案のArray.prototype.fill
一部として追加された、それは指摘する価値があるかもしれません。スレッドで言及されている他のオプションを検討する前に、以下に記載されているポリフィルを使用します。
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
ループコードの最短
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
安全な変数バージョン
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
これは短くなりますfor(var a=[];n--;a[n]=0);
私の最速の機能は:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
ネイティブのプッシュとシフトを使用して項目を配列に追加する方が、配列のスコープを宣言して各項目を参照して値を設定するよりもはるかに高速(約10倍)です。
fyi:最初のループ(カウントダウン中)をFirebug(Firefox拡張機能)で実行すると、一貫して高速になります。
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
TJ Crowderがそれをどのようにして作るのか知りたいです。:-)
while (len--)
..に変更することでより速くすることができます。私の処理時間を約60ミリ秒から約54ミリ秒にした
私はこのプロトがどこかにあることを知っていました:)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
編集:テスト
ジョシュアと他の方法に応じて、私は自分のベンチマークを実行しました、そして私は報告されたそれらとは全く異なる結果を見ています。
これが私がテストしたものです:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
結果:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
したがって、私の計算によると、プッシュは実際には一般的に遅くなりますが、FFの配列が長いほどパフォーマンスは良くなりますが、IEの方が一般的に劣るだけです(驚き)。
b = []...
)は最初の方法よりも10〜15%高速ですが、ジョシュアの答えよりも10倍以上遅いです。
else {this.length=n;}
後にをthis.length
含めます。これにより、既存のinit
長さの配列を別の長さに再初期化するときに、必要に応じて既存の配列が短くなりn
ます。
匿名関数:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
forループで少し短くなります:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
で動作しObject
、内部の内容を変更するだけthis.push()
です。
関数を保存することもできます:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
次を使用して呼び出します:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
既存の配列に要素を追加する:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']