JavaScriptで配列の長さを初期化する方法は?


542

JavaScriptの配列(w3schoolsdevguruを含む)で読んだチュートリアルのほとんどは、var test = new Array(4);構文を使用して整数をArrayコンストラクターに渡すことにより、特定の長さで配列を初期化できることを示唆しています。

この構文をjsファイルで自由に使用した後、ファイルの1つをjsLintを介して実行しました。

エラー:1行目の文字22に問題があります: ')'が必要ですが、代わりに '4'が見つかりました。
var test = new Array(4);
1行目の文字23に問題があります:「;」が必要です 代わりに ')'を見た。
var test = new Array(4);
1行目の文字23の問題:識別子が必要ですが、代わりに「)」が表示されました。

jsLintの動作の説明を読んだ後、jsLintはnew Array()構文があまり好きではなく、[]配列を宣言するときに好むように見えます。

だから私はいくつかの質問があります:

まず、なぜですか?new Array()代わりに構文を使用してリスクを冒していますか?注意すべきブラウザの非互換性はありますか?

次に、角括弧構文に切り替えると、配列を宣言してその長さをすべて1行に設定する方法はありますか、または次のようにする必要があります。

var test = [];
test.length = 4;

標準のjs 一般的に使用しないようにアドバイスしますnew Array()が、サイズを指定しても問題ありません。それはすべて、コンテキスト全体のコードの一貫性に帰着すると思います。
cregox 2017

より厳密な配列構造を事前に割り当てたい人のために、型付き配列があります。注意パフォーマンス上のメリットは変更になる場合があります
rovyko

回答:


398
  1. なぜ長さを初期化したいのですか?理論的にはこれは必要ありません。を使用しlengthて配列が空であるかどうかを確認するすべてのテストで、配列が空ではないことが報告されるため、混乱を招く可能性もあります。
    一部の テストでは、後で配列がいっぱいになると、大きな配列の初期長を設定する方が効率的である可能性がありますが、パフォーマンスの向上(ある場合)はブラウザーごとに異なるようです。

  2. jsLintはnew Array()、コンストラクターがあいまいであるため、好きではありません。

    new Array(4);

    長さ 4の空の配列作成します。

    new Array('4');

    値を含む 配列作成します'4'

コメントについて:JSでは、配列の長さを初期化する必要はありません。動的に成長します。長さをいくつかの変数に格納することができます、例えば

var data = [];
var length = 5; // user defined length

for(var i = 0; i < length; i++) {
    data.push(createSomeObject());
}

13
配列内のオブジェクトの数はユーザーが定義するので、ユーザーに数値を選択させ、その数のスロットで配列を初期化しました。次にfor、配列の長さを反復して埋めるループを実行します。JavaScriptでこれを行うには他の方法もあると思いますので、「なぜこれをしたいのですか?」「他の言語でのプログラミング中に形成された古い習慣のため」です。:)
マイケルマーティンスマッカー'31年

4
@mlms forループに、配列の長さを設定してから反復する代わりに、ユーザー定義の数値を反復させるだけです。それはあなたにとってもっと意味がありませんか?
–ŠimeVidas、2011

151
<blockquote>なぜ長さを初期化したいのですか?理論的にはこれは必要ありません。そして、長さを使用して配列が空であるかどうかを調べるすべてのテストは失敗します。</ blockquote>ええと、パフォーマンスでしょうか?オンザフライで追加するよりも、配列の既存の要素を設定する方が高速です。
コードヘッド、2011年

45
「古いプログラミングの習慣を放棄する時間」というコメントは本当に不要です。適切に構造化された言語は、常にecmascript mombo jamboよりも優れています
user151496 2013

10
@codehead:この引用に応じて:「オンザフライで追加するよりも、配列の既存の要素を設定する方が高速です。」:new Array(10)未定義の要素が10個ある配列は作成されないことに注意してください。これは単に厄介な真実のためにこの回答を参照してください10の長さの空の配列を作成します。stackoverflow.com/questions/18947892/...
Milimetric

598
  • Array(5) 長さ5の配列を提供しますが、値はありません。そのため、それを反復することはできません。

  • Array.apply(null, Array(5)).map(function () {}) 長さ5で値として定義されていない配列を提供します。これで反復できます。

  • Array.apply(null, Array(5)).map(function (x, i) { return i; }) 長さ5、値0、1、2、3、4の配列を提供します。

  • Array(5).forEach(alert)何もせず、Array.apply(null, Array(5)).forEach(alert)5つのアラートを出します

  • ES6私たちにくれるArray.fromので、今あなたも使うことができますArray.from(Array(5)).forEach(alert)

  • 特定の値で初期化する場合、これらは知っておくと役立ちます...
    Array.from('abcde')Array.from('x'.repeat(5))
    またはArray.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]


11
これは私が探していたものです。論理シーケンスにマップを適用したかった。これでうまくいくはずです。ありがとうございました!
jedd.ahyoung 2015年

3
なぜArray.apply()は値として未定義を与えるのですか?
wdanxna

5
@wdanxnaにArray複数の引数が指定されている場合は、argumentsオブジェクトを反復処理して、各値を新しい配列に明示的に適用します。Array.apply配列または長さプロパティを持つオブジェクトを呼び出すと、長さArrayを使用して新しい配列の各値を明示的に設定します。これがArray(5)、5つの省略Array.apply(null, Array(5))の配列を与え、5つの未定義の配列を与える理由です。詳細については、この回答を参照してください。
KylePlusPlus 2015

2
Array(5)と新しいArray(5)の違いは何ですか?
Petr Hurtak 2015年

2
Array.apply(null, Array(5)) 以下のように書くこともできますArray.apply(null, {length: 5})。それほど大きな違いはありませんが、後者の目的は、配列を作成することlength 5であり、配列を含むことではないことは明白です5
AlexMorley-Finch

272

ES2015.fill()を使用すると、次のことが簡単に実行できます。

// `n` is the size you want to initialize your array
// `0` is what the array will be filled with (can be any other value)
Array(n).fill(0)

それはよりもはるかに簡潔です Array.apply(0, new Array(n)).map(i => value)

0in をドロップして.fill()引数なしで実行することが可能で、配列がで埋められundefinedます。(ただし、これはTypescriptでは失敗します


1
@AralRoca MDNページで提供されるポリフィルを常に使用するか、Modernizrの使用を検討できます。
AP。

4
はい、コメントする前に試してください
AP。

1
@GarretWilsonおよび@Christianこれは仕様に含まれています。When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments
AP。

1
@AP。、ゼロは冗長です。行うArray(n).fill()
パチェリエ

2
@Pacerier 0は冗長だとは思いません。es6型の定義によると、これは関数のシグネチャです。したがって、fill値はオプションではないようです。関数呼び出しが上に記述されているため、Typescriptのコンパイルは失敗します。
Micha Schwab

151
[...Array(6)].map(x => 0);
// [0, 0, 0, 0, 0, 0]

または

Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]

注:空のスロットはループできません。 Array(4).forEach(() => …)


または

typescript safe

Array(6).fill(null).map((_, i) => i);
// [0, 1, 2, 3, 4, 5]

または

関数を使用したクラシックな方法(任意のブラウザで機能します)

function NewArray(size) {
    var x = [];
    for (var i = 0; i < size; ++i) {
        x[i] = i;
        return x;
    }
}

var a = NewArray(10);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ネストされた配列の作成

2D配列を作成すると、fill直感的に新しいインスタンスが作成されます。しかし、実際に行われるのは、同じ配列が参照として格納されることです。

var a = Array(3).fill([6]);
// [  [6], [6], [6]  ]

a[0].push(9);
// [  [6, 9], [6, 9], [6, 9]  ]

解決

var a = [...Array(3)].map(x => []);

a[0].push(4, 2);
// [  [4, 2], [], []  ]

したがって、3x2配列は次のようになります。

[...Array(3)].map(x => Array(2).fill(0));
// [  [0, 0], [0, 0], [0, 0]  ]

N次元配列

function NArray(...dimensions) {
    var index = 0;
    function NArrayRec(dims) {
        var first = dims[0], next = dims.slice().splice(1); 
        if(dims.length > 1) 
            return Array(dims[0]).fill(null).map((x, i) => NArrayRec(next ));
        return Array(dims[0]).fill(null).map((x, i) => (index++));
    }
    return NArrayRec(dimensions);
}

var arr = NArray(3, 2, 4);
// [   [  [ 0,  1,  2,  3 ] , [  4,  5,  6,  7]  ],
//     [  [ 8,  9,  10, 11] , [ 12, 13, 14, 15]  ],
//     [  [ 16, 17, 18, 19] , [ 20, 21, 22, 23]  ]   ]

チェス盤を初期化する

var Chessboard = [...Array(8)].map((x, j) => {
    return Array(8).fill(null).map((y, i) => {
        return `${String.fromCharCode(65 + i)}${8 - j}`;
    });
});

// [ [A8, B8, C8, D8, E8, F8, G8, H8],
//   [A7, B7, C7, D7, E7, F7, G7, H7],
//   [A6, B6, C6, D6, E6, F6, G6, H6],
//   [A5, B5, C5, D5, E5, F5, G5, H5],
//   [A4, B4, C4, D4, E4, F4, G4, H4],
//   [A3, B3, C3, D3, E3, F3, G3, H3],
//   [A2, B2, C2, D2, E2, F2, G2, H2],
//   [A1, B1, C1, D1, E1, F1, G1, H1] ]

1
a[0].push(9); // [ [6, 9], [6], [6] ] でなければならない a[0].push(9); // [ [6, 9], [6, 9], [6, 9] ] 各ネストされた配列を参照として格納されるため、そう変異つのアレイは、残りの影響します。あなたは私が思うにそれをタイプミスしたかもしれません:)
Alex_Zhong

@Alex_Zhong truそれは編集で失ってしまいました
Vlad

68

一番短い:

[...Array(1000)]

11
賛成ですが、1つの注意点があります。絶対にJSで行を開始するときは、aを[使わずに;上記の行を逆参照しようとするためです。だから、コードのどの部分で予想通り、このラインを使用する安全な方法は、次のようになります;[...Array(1000)]//.whateverOpsNeeded()
AP。

あんまり。開発者ツールを試してください。 [...Array(5)].map((item, index) => ({ index })) これを試すだけでなく:[...Array(5)]; console.log('hello');
マイケルMammoliti

2
複数行のjsファイルで使用してみてください。最初の行がconst a = 'a'次の行である場合[...Array(5)].//irrelevent。最初の行は何に解決すると思いますか?それは次のようになりますconst a = 'a'[...Array(5)]:につながると思われるUncaught SyntaxError: Unexpected token ...
AP。

7
それは本当ですが、この場合、問題はどこか別のところにあると私は言うでしょう、今日はセミコロンとリンティングが重要です。
Michael Mammoliti

8
@APその例は、多くのスタイルガイドがすべてのステートメントをセミコロンで終了することを義務付けている理由です。const a = 'a'その場合、Lintエラーになります。とにかく、それは本当にこの答えとは何の関係もありません。
graup

41

ES6 Array.fromではArray「配列のような」オブジェクトまたは反復可能なオブジェクトからを作成できるようになりました。

Array.from({length: 10}, (x, i) => i);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

この場合{length: 10}「配列のような」オブジェクトの最小限の定義、つまりlengthプロパティのみが定義された空のオブジェクトを表します。

Array.from 結果の配列にマップする2番目の引数を許可します。


2
@dain [... Array(10)]の方がいいと思いますstackoverflow.com/a/47929322/4137472
Alexander Shutau

1
なぜ良いのですか?Arrayコンストラクタの使用は推奨されて
おら

26

これにより、長さプロパティが4に初期化されます。

var x = [,,,,];

3
それは賢いです。変数を使用して長さを設定することはできないため、コンストラクターの柔軟性はありませんが、私が最初に言ったように、質問に答えます。+ 1です。
Michael Martin-Smucker、2011年

12
パフォーマンスが本当に重要である300のアイテムに対してそれを行うと想像してください!
Marco Luglio

9
このような小さいサイズの配列を事前に割り当てる場合、おそらくパフォーマンスの向上はあまりありません。より大きなアレイを作成すると、パフォーマンスの違いがよりよく認識されます。そして、それらの場合、それらをコンマで初期化することは少し圧倒されるでしょう。
Marco Luglio

6
なるほど、これが原因で最後のコンマの異なるブラウザで異なる結果をもたらすだろうと思い、時には4、時には5 stackoverflow.com/questions/7246618/...
jperelli

1
いかがvar size = 42; var myArray = eval("["+",".repeat(size)+"]");ですか?(それほど深刻ではありません。)
xoxox

15

1行で長さを設定できる機能的なソリューションが提案されていないことに驚いています。以下はUnderscoreJSに基づいています:

var test = _.map(_.range(4), function () { return undefined; });
console.log(test.length);

上記の理由により、配列を特定の値に初期化する必要がない限り、これは避けます。Lo-dashやLazyなど、範囲を実装する他のライブラリがあり、パフォーマンス特性が異なる可能性があることに注意してください。


ここではアンダースコアの黒魔術は本当に必要ありません。依存性は砂糖のようですが、最初は甘いように見えますが、気付かないうちに糖尿病になります。
Romain Vincent

9

人々はあなたの古い習慣をまだあきらめないでください。メモリを一度割り当ててから、その配列のエントリを操作する(古い)場合と、配列が大きくなるにつれて何度も割り当てる場合との間で速度に大きな違いがあります(これは必然的に、システムが他の推奨される方法で内部的に行うことです)。 。

より大きな配列で何かクールなことをしたいまでは、もちろんこれは問題になりません。それはそうです。

現在のところ、JSにはアレイの初期容量を設定するオプションがないように見えるので、以下を使用します...

var newArrayWithSize = function(size) {
  this.standard = this.standard||[];
  for (var add = size-this.standard.length; add>0; add--) {
   this.standard.push(undefined);// or whatever
  }
  return this.standard.slice(0,size);
}

関連するトレードオフがあります:

  • このメソッドは、関数の最初の呼び出しには他のメソッドと同じくらい時間がかかりますが、(より大きな配列を要求しない限り)以降の呼び出しにはほとんど時間がかかりません。
  • standard配列は永久にあなたが求めている最大の配列として多くのスペースとして確保ありません。

しかし、それがあなたのやっていることに合っているなら、見返りがあるかもしれません。非公式なタイミング

for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}

かなり高速(n = 1000000の場合、10000で約50ミリ秒かかり、約5秒かかりました)

for (var n=10000;n>0;n--) {
  var b = [];for (var add=10000;add>0;add--) {
    b.push(undefined);
  }
}

1分をはるかに超える(同じChromeコンソールで10000の場合は約90秒、または約2000倍遅い)。これは単なる割り当てではなく、10000プッシュ、forループなどでもあります。


配列の最後に到達するたびに複製する場合でも、n個の値を挿入する複雑さはO(n)であるため、複雑さに違いはありません(ただし、遅くなります)。
Tomer Wolberg、2018

よくキャッチされた@TomerWolberg、私は私の言い回しを変更しました。これは、pushメソッドが個々のメンバーのスライスによる初期化/コピーよりも複雑であるかどうかの問題です。AFAIKは、どちらも一定の時間であると考えていますが、少なくとも可能性はあるので、代わりに「速度」という言葉を使用しました。
2018年

8

(これはおそらくコメントとしては優れていましたが、長くなりすぎました)

したがって、これを読んだ後、事前割り当てが実際に高速であるかどうかを知りました。ただし、このブログではhttp://www.html5rocks.com/en/tutorials/speed/v8/にアドバイスするいくつかのヒントを提供しました。

だからまだわからないので、私はそれをテストにかけました。そして結局のところ、それは実際には遅いようです。

var time = Date.now();
var temp = [];
for(var i=0;i<100000;i++){
    temp[i]=i;
}
console.log(Date.now()-time);


var time = Date.now();
var temp2 = new Array(100000);
for(var i=0;i<100000;i++){
    temp2[i] = i;
}
console.log(Date.now()-time); 

このコードは、数回のカジュアルな実行後に次の結果をもたらします。

$ node main.js 
9
16
$ node main.js 
8
14
$ node main.js 
7
20
$ node main.js 
9
14
$ node main.js 
9
19

3
興味深いことに、それは予想外に思われので、私はJSPerfテストを行いまし。Chromeの結果はノードテストと一致しますが、FirefoxとIEは、アレイにスペースを事前に割り当てるとわずかに速くなります。
Michael Martin-Smucker、2014

1
@ MichaelMartin-Smucker Wait ...これは、V8が実際に完全に最適化されておらず、完璧ではないことを意味しますか?!?!?:P
Zeb McCorkle 2014年

1
@ MichaelMartin-Smucker-私はちょうどあなたのjsperfをChromeバージョン42.0.2311.90で実行しました(具体的には-Windows Server 2008 R2 / 7 64ビットの32ビットChrome 42.0.2311.90でのテスト)、動的サイズのアレイは69%遅くなりました。
Yellen 2015

1
同上。(私は元のノードテストを書いた)動的なサイズのウィンドウのchrome 42.0.2311.90では81%遅くなりました:)。しかし、最初のテストは1年以上前のことでした。スリッピン、スリッピン....
j03m

1
魅力的... jsperfの結果から、Chrome 38で事前割り当て済みが大幅に向上したようです。未来!
Michael Martin-Smucker、2015

8
var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6

2
はい。ただし、console.log(arr)は、[5: 0]これが疎な配列であり、おそらく必要なものではないことを示しています。
dreftymac 2014年

7

ここに別の解決策があります

var arr = Array.apply( null, { length: 4 } );
arr;  // [undefined, undefined, undefined, undefined] (in Chrome)
arr.length; // 4

の最初の引数apply()はthisオブジェクトバインディングであり、ここでは気にしませんnull。そのため、に設定します。

Array.apply(..)Array(..)関数を呼び出し、{ length: 3 }引数としてオブジェクト値を展開しています。


なぜこの回答が反対票を投じたのか理解できません。それは実際には素晴らしいハックです。new Array(n)このような配列の初期化には使用できないことを意味しますnew Array(n).map(function(notUsed,index){...})が、このアプローチでは、@ zangwが述べたように、それを実行できます。私からの+1。
Victor.Palyvoda 2016

3

配列コンストラクターにはあいまいな構文があり、JSLintは結局あなたの気持ちを傷つけるだけです。

また、サンプルコードが壊れているため、2番目のvarステートメントでが発生しSyntaxErrorます。length配列のプロパティを設定しているtestので、別のの必要はありませんvar

オプションに関する限り、これarray.lengthが唯一の「クリーン」なオプションです。質問は、なぜ最初にサイズを設定する必要があるのですか?その依存関係を取り除くためにコードをリファクタリングしてみてください。


おっと、その2番目に良い目をvar test。それは、ずさんなコピーアンドペーストでした。
Michael Martin-Smucker、2011年

@IvoWetzel、パフォーマンスを改善するためにサイズを設定したい。JS配列は動的配列です。サイズ(または容量)を設定しない場合、JSはデフォルトサイズの配列を割り当てます。次に、収まるよりも多くの要素を追加する場合は、配列を拡張する必要があります。つまり、内部で新しい配列を割り当て、すべての要素をコピーします。
ドミ

3

Arrayの長さが一定であると仮定します。JavaScriptでは、これは私たちがしていることです:

const intialArray = new Array(specify the value);


2

上で説明したように、使用new Array(size)はやや危険です。直接使用する代わりに、「配列作成関数」内に配置します。この関数にバグがないことを簡単に確認でき、new Array(size)直接呼び出す危険を回避できます。また、オプションでデフォルトの初期値を指定することもできます。このcreateArray関数はまさにそれを行います:

function createArray(size, defaultVal) {
    var arr = new Array(size);
    if (arguments.length == 2) {
        // optional default value
        for (int i = 0; i < size; ++i) {
            arr[i] = defaultVal;
        }
    }
    return arr;
}

1

ほとんどのfill場合、配列に対して推奨されます。それ以外の場合は、「反復できない」ためですが、これは正しくありません。空の配列を反復できforEachます。whileループ、for ofループ、for iループは正常に機能します。

const count = Array(5);

動作しません。

console.log('---for each loop:---');
count.forEach((empty, index) => {
    console.log(`counting ${index}`);
});

これらの作業:

console.log('---for of loop:---');
for (let [index, empty] of count.entries()) {
  console.log(`counting for of loop ${index}`);
}

console.log('---for i loop:---');
for (let i = 0, il = count.length; i < il; ++i) {
  console.log(`counting for i loop ${i}`);
}

console.log('---while loop:---');
let index = 0;
while (index < count.length) { 
  console.log(`counting while loop ${index}`); 
  index++; 
}

上記の例でこのフィドルを確認してください。

また、角度*ngForは空の配列でうまく機能します:

<li *ngFor="let empty of count; let i = index" [ngClass]="
  <span>Counting with *ngFor {{i}}</span>
</li>

-1

を使用して配列の長さを設定できます array.length = youValue

だからそれは

var myArray = [];
myArray.length = yourValue;

-3

使用すべきでない理由new Arrayは、次のコードで示されています。

var Array = function () {};

var x = new Array(4);

alert(x.length);  // undefined...

他のいくつかのコード、配列変数を混乱させる可能性があります。誰もがそのようなコードを書くのは少し遠いことですが、それでも...

また、Felix Kingが言ったように、インターフェースは少し一貫性がなく、追跡が非常に難しいバグにつながる可能性があります。

長さ= xで、未定義で埋められた配列が必要な場合(new Array(x)そうするように)、これを行うことができます:

var x = 4;
var myArray = [];
myArray[x - 1] = undefined;

alert(myArray.length); // 4

48
この推論によれば、alertandを使用すべきではありませんundefined。他のコードがそれらを混乱させる可能性があるためです。2番目の例は、より読みにくくnew Array(4)、同じ結果が得られません:jsfiddle.net/73fKd
Alexey Lebedev

25
この答えは奇妙です
マルコデマイオ2015

6
JavaScriptでグローバルオブジェクトをいじり回すことは避けられません。単にそれをしないか、人々がそうする場所でフレームワークを使用してください。
Richard Connamacher、2015

現在、chrome replで:j = new Array(4); j.length; //結果は4
Parris
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.