ゼロで埋められたJavaScript配列を作成する最も効率的な方法は?


602

JavaScriptで任意の長さのゼロで満たされた配列を作成する最も効率的な方法は何ですか?


7
これに関する実際のデータ:jsperf.com/zeroarrayjs
Web_Designer

7
ES6のfillでは、これをネイティブに行うことができます。
サルバドールダリ

1
arr = new Array(length + 1).joint(character).split( '');
ジョーダンステファネリ2015年

4
2016年更新:別のカスタムベンチマーク: jsfiddle.net/basickarl/md5z0Lqq
K-SOの毒性が高まっています。

1
let i = 0; Array.from(Array(10), ()=>i++);
Bart Hoekstra、2017年

回答:


543

ES6が導入しArray.prototype.fillます。次のように使用できます。

new Array(len).fill(0);

高速かどうかはわかりませんが、短くて自己記述的なので気に入っています。

IEにはまだありません(互換性を確認してください)が、利用可能なポリフィルがあります


15
充填が速い。new Array(len)痛いほど遅いです。(arr = []).length = len; arr.fill(0);どこでも見られる最速のソリューションについて...または少なくとも
同調

7
@PimpTrizkit arr = Array(n)(arr = []).length = n仕様に従って同じように動作します。実装によってはより高速になる場合もありますが、大きな違いはないと思います。
Oriol

2
さて、私は多次元配列でそれをテストし始めました、そしてそれは私のテストケースを非常にスピードアップするようでした。FF41およびChrome45.0.2454.99 mでさらにテストを行ったところです。はい、私は自分自身を説明するために本当にもっと多くのスペースが必要だったと思います。私のテストのほとんどは、私が認めるバイアスでした。しかし、これをチェックしてください。変数を事前定義し、この行だけ(arr = []).length = 1000;arr = new Array(1000);速度に対して使用して、ChromeとFFの両方でテストしnewます。速度が非常に遅くなります。さて、配列の長さが小さい場合.. <50かそこらについて言ってください...するとnew Array()、パフォーマンスが向上するようです。しかし..
Pimp Trizkit 2015

4
...私はこの部分を逃したことを認めますarr.fill(0) ... テストに2行目を追加すると... ...すべてが多少変更されます。これで、new Array()配列のサイズが100000を超える場合を除いて、ほとんどの場合で使用が速くなります。その後、速度の増加を再び確認できます。しかし、実際にゼロを事前に入力する必要がなく、空の配列の標準ファリシーを使用できる場合。そう(arr = []).length = xすれば、ほとんどの場合、テストケースで非常に速くなります。
Pimp Trizkit 2015

4
配列(mapまたはforEachなど)を反復処理するには、値を設定する必要があります。そうしないと、これらのインデックスがスキップされます。設定する値は、未定義であっても、何でもかまいません。例:new Array(5).forEach(val => console.log('hi'));vsを試してくださいnew Array(5).fill(undefined).forEach(val => console.log('hi'));
ArneHugo 2016年

387

これは古いスレッドですが、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]

6
正解です。トリックを説明してもらえますArray.apply(null, new Array(5)).map(...)か?(new Array(5))。map(...)を単純に実行すると、仕様が示すように機能しません
Dmitry Pashkevich

36
(ところで、私たちは本当に必要はありませんnewあなたがないとき)Array(5):あなたはちょっと、このようになっていることをオブジェクト作成している{ length: 5, __proto__: Array.prototype }試みを- console.dir( Array(5) )。それはどんな性質を持っていないことに注意してください012、などしかし、あなたapplyがたことをArrayコンストラクタ、それは言ってようなものですArray(undefined, undefined, undefined, undefined, undefined)。そして、あなたはちょっとのようなオブジェクトを取得します{ length: 5, 0: undefined, 1: undefined...}mapプロパティ01などで機能するため、例は機能しませんが、使用するapplyと機能します。
zertosh 2013

4
の最初のパラメータ.applyは、実際にはにしたいものですthis。これらの目的にとってthisは問題ではありません-私たちは本当に「機能」を広げるパラメータにのみ関心.applyがあるので、どんな値でもかまいません。私は次のようにnullそれの安いので、あなたはおそらく使用したくない{}か、[]あなたが理由もなくオブジェクトをインスタンス化すると思いますので、。
zertosh 2013

2
また、サイズ+割り当てによる初期化は、プッシュよりもはるかに高速です。テストケースを参照jsperf.com/zero-fill-2d-array
Colin

2
Array.apply(null、Array(5))。map(x => 0)はどうですか?少し短いです!
Arch Linux Tux 2016年

97

事前計算された値で配列を埋めるエレガントな方法

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]

その投稿には多くのパーラーのトリックが含まれていますが、プロダクションコードに到達しないことを期待しています:)
Eric Grange

このrepeatトリックは本番では絶対に必要ではありませんが、Array.from()完全に問題ありません:-)
Lucio Paiva

実際には、ここではArray.from()は基本的に配列を作成し、それをmap()で繰り返し、各項目で関数を呼び出して新しい配列を作成し、最初の配列を破棄しています...小さな配列の場合、これは無害で、より大きな配列の場合、これは、人々がブラウザを「メモリの独り占め」と呼ぶようなパターンです:)
Eric Grange

大規模な配列を扱う人々は、これよりもよく知っているべきです。ただし、一般的なアプリの場合、すぐに破棄される通常サイズのaux配列(最大10k要素)を作成することは完全に問題ありません(余分な配列の作成を回避した場合と同じ時間がかかります-最新のChromeでテスト)。このような場合、小さなパフォーマンスの最適化よりも読みやすさが重要になります。O(n)時間については、要素ごとに異なるものを計算する必要がある場合に必要です(私の回答の主な主題)。この議論は非常に興味深いものであり、あなたがそれを提起してくれてうれしいです!
Lucio Paiva、

88

要するに

最速のソリューション

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つのテストケースでテストします

  • 小さな配列-10要素- ここでテストを実行できます
  • 大きな配列-1M要素- ここでテストを実行できます

結論

  • 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の結果の例

ここに画像の説明を入力してください


Chrome 77でいくつかのテストを実行しただけで、push()を使用した単純なループはfill()より2倍高速です...
Eric Grange、

@EricGrange私は答えを更新します-下部であなたの命題でベンチマークへのリンクを更新します:ケースP- let a=[]; for(i=n;i--;) a.push(0);しかし、それは4倍遅いですfill(0)-したがって、私はそのケースの画像魔女を更新しません。
KamilKiełczewski、

2
素晴らしい測定。分析:Gは、反復ごとに配列のサイズを変更するために遅く、サイズ変更は新しいメモリ割り当てを行うことを意味します。A、B、Mのサイジングは1回だけなので、高速です。+1
ローランド

@gman実際にあなたが正しいしている-私はそれを見逃している可能性がどのように理解していない-私は新しいテストを実行し、より多くの詳細を更新答え-ありがとう:)
カミルKiełczewskiを

63

すでに述べたES 6のfillメソッドはこれをうまく処理します。最近のほとんどのデスクトップブラウザーは、現在のところ必要なArrayプロトタイプメソッド(Chromium、FF、Edge、およびSafari)を既にサポートしています[ 1 ]。MDNで詳細を調べることができます。簡単な使用例は

a = new Array(10).fill(0);

現在のブラウザのサポートを考えると、読者が最新のデスクトップブラウザを使用していることが確実でない限り、これを使用するように注意する必要があります。


4
参照タイプを入力すると、すべての参照タイプで同じ参照になります。新しいArray(10).fill(null).map(()=> [])は、これを回避する簡単な方法です(最初は私を焦がしました)
John Culviner

4
2016年更新:この方法は、他のすべてを水から吹き飛ばします。ベンチマークについては、ここをクリックしてください: jsfiddle.net/basickarl/md5z0Lqq
K-SOの毒性が高まっています。

これは配列に対して機能します。a = Array(10).fill(null).map(() => { return []; });
アンディ

2
@AndrewAnthonyGerst Terser:a = Array(10).fill(0).map( _ => [] );
Phrogz 2017

50

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>

要素にアクセスするだけで(それらを削除するのではなく)、事前に割り当てられているので、ここで逆方向の入力が問題になるかどうかはわかりません。私が間違っている?
トリプティク

後方の塗りつぶしのポイントは、特に配列とは関係ありません。それは、しばらくの間のエスケープ条件と関係があります-偽の0は、ループを非常に効率的に終了します
annakata

(私はこのコードが実際にそれを利用していないことに気付いたばかりですが)
annakata 09

@ annakata、0は有効なインデックスであるため、ここではそれを使用できません。
トリプティク

@triptych:真実ではありません。必要なのは正しい順序です-私の投稿を参照してください
アナカタ09

34

デフォルトUint8ArrayではUint16ArrayUint32Arrayクラスは値としてゼロを保持するため、複雑な塗りつぶし手法は必要ありません。次のようにしてください:

var ary = new Uint8Array(10);

配列のすべての要素はaryデフォルトでゼロになります。


5
これはいいですが、この心のノートは例えば、通常の配列と同じように扱うことができないArray.isArray(ary)ですfalse。長さも読み取り専用なので、次のように新しいアイテムをプッシュすることはできませんary.push
MusikAnimal

Fwiwはすべての型付き配列を0デフォルト値のままにします。
jfunk 2017年

2
@MusikAnimalはArray.from(new Uint8Array(10))、通常の配列を提供します。
Tomas Langkaas 2017年

@TomasLangkaas:はい、しかし別の答えは、Array(n).fill(0)本当に必要なものがJS配列である場合、それはChrome の約5倍遅いことを示しています。TypedArrayを使用できる場合.fill(0)、特にデフォルトの初期化子値を使用できる場合は、これはよりもはるかに高速です0。C ++のように、fill-valueとlengthを取るコンストラクタはないようですstd::vector。ゼロ以外の値の場合は、ゼロに設定されたTypedArrayを作成してそれを埋める必要があります。:/
Peter Cordes

29

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]

23
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-inforEachなど


3
iローカル変数は無関係ではありませんか? length値で渡されるため、直接デクリメントできるはずです。
ショーンブライト

3
これは一見素晴らしいように見えますが、残念ながら、araryの任意のポイント(などarr[i] = value)に値を割り当てるのは非常に遅いです。最初から最後までループしてを使用する方がはるかに高速arr.push(value)です。私はあなたの方法を好むので、それは迷惑です。
Nick Brunt 2014

19

オブジェクト表記の使用

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 = [];

プロトタイプが変更されます

とにかく、私はこの操作の効率や速度に過度に懸念することはありません。ゼロを含む任意の長さの配列をインスタンス化するよりもはるかに無駄でコストのかかることは他にもたくさんあります。


5
エラー... nullこの配列にs はありませんvar x = new Array(7);
kangax '18

5
実際、配列は新しいArray(n)で何も入力されず、「未定義」であっても、配列の長さの値をnに設定するだけです。これを確認するには、(new Array(1))。forEach(...)を呼び出します。forEachは、[undefined]で呼び出す場合とは異なり、決して実行されません。
JussiR 2013

4
new Array(7)「未定義で満たされた」配列作成しませ。これは、作成し、空の長さ7と配列
RobG

1
@RobGの発言が重要であるため、回答の一部を再検討することをお勧めします(発言が真実であれば、マッピングははるかに簡単だったでしょう)
Abdo

1
最近できます(new Array(10)).fill(0)
ハビエルデラロサ

18

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;
}

1
また、var array = []宣言をforループの最初の部分にコンマで区切って実際にスローすることもできます。
damianb 2012年

私はdamianbによるその提案が好きですが、インクリメントの前に割り当てとコンマを忘れずに置いてください!`for(var i = 0; i <length; array [i] = val、i ++);
パンストレス

他のすべての人があなたの2番目のものに欠けていることを行い、配列の長さがlengthすでに与えられた値に設定され、それが常に変化しないようにします。私のマシンで、100万長のゼロの配列を40ミリ秒から8ミリ秒に変更しました。
ジョナサングレイ

このソリューションを1つのライナーにリファクタリングすると、速度が10〜15%向上するようです。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このバージョンでは高速であると思われます)
Pimp Trizkit

私はまた、私のテストでそれを指摘します。適切な数のテストケースで、上記の最終バージョンは3倍から10倍以上高速に実行されるようです...理由がよく
わかり

13

コードの実行中にさまざまな長さの多くのゼロで満たされた配列を作成する必要がある場合、これを達成するために見つけた最も速い方法は、このトピックで説明されている方法の1つを使用して、ゼロの長さの配列を一度作成することです決して超えられないことがわかっていて、必要に応じてその配列をスライスします。

たとえば、(上記で選択した回答の関数を使用して配列を初期化する)、長さがmaxLengthのゼロで満たされた配列を、ゼロ配列を必要とするコードから見える変数として作成します。

var zero = newFilledArray(maxLength, 0);

ここで、必要な長さのゼロで満たされた配列が必要になるたびに、この配列をスライスしますrequiredLength < maxLength

zero.slice(0, requiredLength);

私はコードの実行中に何千回もゼロで満たされた配列を作成していましたが、これによりプロセスが大幅にスピードアップしました。


13
function zeroFilledArray(size) {
    return new Array(size + 1).join('0').split('');
}

3
new Array(size+1).join("x").split("x").map(function() { return 0; })実際の数値を取得するために使用することもできます
Yuval

6
@ユヴァルまたはちょうどnew Array(size+1).join('0').split('').map(Number)
ポール

11

私は反対しません:

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]


10

私が通常行う方法(そして驚くほど高速です)はを使用してい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

  1. フレデリク・ゴットリーブ-6.43
  2. サムバーナム-4.83
  3. エリ-3.68
  4. ジョシュア2.91
  5. マシュー・クランリー-2.67
  6. ブドゥラン-2.55
  7. アレンライス-2.11
  8. カンガス-0.68
  9. Tj。クラウダー-0.67
  10. zertosh-エラー

Firefox 20.0

  1. アレンライス-1.85
  2. ジョシュア-1.82
  3. マシュー・クランリー-1.79
  4. ブドゥラン-1.37
  5. フレデリク・ゴットリーブ-0.67
  6. サムバーナム-0.63
  7. エリ-0.59
  8. カガックス-0.13
  9. Tj。クラウダー-0.13
  10. zertosh-エラー

最も重要なテスト(少なくとも私にとっては)がありません:Node.jsです。Chromeのベンチマークに近いと思います。


これは私の指にとって、そして私の目にとって最も効率的な方法です。しかし、Chromeの場合は非常に低速です(そのjsperfによると、99%遅い)。
Orwellophile 2016年

1
:あなたの友人のMac上の問題が関連しているのだろうかstackoverflow.com/questions/39129200/...または多分Array.sliceはUInt8Arrayを処理し、初期化されていないメモリをリークされませんでしたか?(セキュリティ問題!)
robocat 2017

@robocatグッドキャッチ!私がよく覚えているのは、Node.js 0.6または0.8を使用していたことです。何らかのリークについて考えましたが、本番スタックでは再現できなかったため、無視することにしました。
デュラム2017

10

ロダッシュまたはアンダースコアの使用

_.range(0, length - 1, 0);

または、既存の配列があり、同じ長さの配列が必要な場合

array.map(_.constant(0));

アンダースコアを使用しているので、この回答を追加してくれてうれしいです。これに何かがあることはわかっていましたが、まだそれを見つけることができませんでした。これを使用してオブジェクトの配列を作成できたらいいのに
PandaWood 2014年

@PandaWood _.range(0、length -1、0).map(Object.new)だと思います。
djechlin 2014年

あるはずだ_.range(0, length, 0)と思います。Lodashには最終値が含まれていません
user4815162342


8

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再定義されない変数と再定義される変数に使用しますletMDNAirbnbのスタイルガイドは、ベストプラクティスの詳細については、行くには絶好の場所です。質問は構文に関するものではありませんでしたが、JSの初心者がこれらの新旧の答えの範囲を検索するときに、これらの新しい標準について知っていることが重要です。


8

まったく新しいアレイを作成するには

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)]);


6

回答にこのメソッドが表示されなかったので、ここにあります:

"0".repeat( 200 ).split("").map( parseFloat )

結果として、長さ200のゼロ値配列が得られます。

[ 0, 0, 0, 0, ... 0 ]

このコードのパフォーマンスについてはわかりませんが、比較的小さな配列に使用しても問題にはなりません。


5
最速でも最短でもありませんが、ソリューションの多様性への素晴らしい貢献です。
7vujy0f0hy 2017


4

この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('');
}

2
はい、ワイルドです。これは、新しいArray(len)を使用するよりも高速です。だが!Chromeでは、その後のそのデータの読み取りにかなり時間がかかることがわかりました。(new Array(len)を使用)0.365:配列の作成4.526:畳み込みの実行10.75:畳み込みの完了(concatの使用)0.339:配列の作成0.591:畳み込みの実行// OMG、高速18.056:コンボリューション完了
Brooks

4

私は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)



4

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;
  };
}

4

ループコードの最短

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;

2
長さが定義された変数であることを考えると、nこれは短くなりますfor(var a=[];n--;a[n]=0);
トマスLangkaas


3

私の最速の機能は:

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ミリ秒にした
nickf

マシュー・クランブリーの答えは、実際にはこれを上回っています(30ms)!
nickf 2009

3

私はこのプロトがどこかにあることを知っていました:)

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の方が一般的に劣るだけです(驚き)。


私はこれをテストしました。2番目の方法(b = []...)は最初の方法よりも10〜15%高速ですが、ジョシュアの答えよりも10倍以上遅いです。
nickf 2009

私はこれが古代の記事であることを知っています。しかし、おそらくそれは他の人(私のように)にとってまだ興味があるでしょう。したがって、プロトタイプ関数への追加を提案したいと思います:-checkのelse {this.length=n;}後にをthis.length含めます。これにより、既存のinit長さの配列を別の長さに再初期化するときに、必要に応じて既存の配列が短くなりnます。
cars10m 2015

2

匿名関数:

(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']

パフォーマンス:http : //jsperf.com/zero-filled-array-creation/25

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.