JavaScript配列操作

多重操作メソッド VS for

他の言語でもそうですが、これらの配列操作のメソッドの方がforEachよりも速いのですか?

実は逆で、forEach のほうが速いことが多いです。

flatMap や filter や map をチェーンすると、各ステップで中間配列が新たに生成されるためメモリとCPUのオーバーヘッドが増えます。

ただし実用上はどちらでも問題ないことがほとんどです。

テトリスのボードサイズ(20×10 = 200セル)程度では差はナノ秒レベルで、人間には感知できません。パフォーマンスが問題になるのは数万〜数百万件のデータを扱う場合です。

なので選択基準としては:

  • 読みやすさ・意図の明確さ → flatMap/filter チェーン
  • パフォーマンスが最優先 → for...of や forEach

が一般的な使い分けです。

配列.flat()

JavaScriptの.flat()`メソッドは、多次元配列(ネストされた配列)を、指定した深さまで平坦化(1次元の配列に平らにならす)した新しい配列を返す機能です。引数を省略すると、初期値として1階層だけ平坦化され、元の配列は変更されない(非破壊)という特徴があります。

flat()メソッドの主な効果・特徴

  • ネストを解消(平坦化)[[1, 2], [3, 4]] が [1, 2, 3, 4] のように、入れ子構造を解除します。
  • 深さの指定flat(1)(既定値)は1階層のみ、flat(2) は2階層下まで平坦化します。
  • 深さ無限flat(Infinity) を指定すると、ネストがどれほど深くても完全に1次元の配列にできます。
  • 空要素の削除: 配列内の空のスロット(疎配列)は削除されます。
  • 新規配列の作成: 元の配列を変更せず、新しい配列を返します(シャローコピー)。

使用例

関連メソッド・注意点

  • flatMap()map()(変換)と flat()(平坦化)を同時に実行します。マッピング後に配列を平坦化したい場合に最適です。
  • 非破壊的flat() は新しい配列を返します。
  • 対応ブラウザ: ES2019で追加された機能で、現代のブラウザではほぼすべて対応しています。

配列内の配列の要素を一度に取り出したり、多次元配列の要素数を数えたりする際に非常に便利です。

配列.filter()

配列内の各要素に対して指定した条件(コールバック関数)をテストし、真(true)を返した要素のみを抽出して新しい配列を作成します。元の配列は変更されません。

基本的な使い方

構文

element: 配列の現在の要素。
index (オプション): 現在の要素のインデックス。
array (オプション): filterが呼び出された配列

実践的な活用例

1. オブジェクトの配列から特定の条件に合うものを抽出 

2. 配列から不要なデータを削除

3. 数値の範囲でフィルタリング

注意点

  • 空配列: 条件に一致する要素がなかった場合、空の配列[]が返されます。
  • シャローコピー: 抽出された配列は、元の配列の要素の「シャローコピー(参照)」です。オブジェクトのプロパティを変更すると、元のオブジェクトも変更されます。

.map()

JavaScriptの.map()メソッドは、配列の全要素に対して指定した関数を適用し、その結果から新しい配列を作成する(元の配列は変更しない)高階関数です。データを変換・加工して新しいリストを生成する際に、for文よりも簡潔で宣言的に記述できる効果があります。

主な効果と特徴

  • 非破壊的なデータ変換: 元の配列を変更せず、加工された新しい配列を返します。
  • コードの簡潔化: for文で配列を回してpushする手間が省け、コードが見やすくなります。
  • 要素ごとの一括処理: すべての要素に同じ処理を一度に適用できます。

基本構文とコード例

forEachメソッドとの違い

  • map(): 新しい配列を返す
  • forEach(): 何も返さない(処理のみ実行する)

データ操作やReactなどのフロントエンド開発で、配列をUIの要素(JSX)に変換する際によく使用されます。

配列1.push([…配列2[0])]

「配列2の最初の要素(これも配列である想定)の中身をばらして、配列1の末尾に個別に追加する」という意味になります。

具体的には、破壊的な(元の配列を変更する)要素追加操作です。

1. 意味の分解

  • 配列2[0]: 配列2の最初の要素(配列である必要がある)を参照。
  • [...配列2[0]]: スプレッド構文(...)を使い、配列2[0]の内容を展開して、新しい配列の中に詰め込む。
  • push(...): 展開された要素を、配列1の末尾に追加する。

2. 具体的な動作例

3. なぜ [...配列2[0]] のような記述が必要か?

もし単に 配列1.push(配列2[0]) と書いた場合、配列1の中に、配列2[0](配列そのもの)が「1つの要素」として入ってしまうため、二次元配列(ネストした配列)になります。

4. まとめ

このコードは、「配列の中にある配列を、別の配列に平坦化して追加したい」場合によく使われるテクニックです。

注意点

  • 配列2[0] が配列でない場合、エラーになります。
  • push は元の配列(配列1)を変更(破壊)します。

同様の動作は 配列1.push.apply(配列1, 配列2[0]) でも可能ですが、スプレッド構文(...)の方がモダンで読みやすいとされています。

配列.every()

JavaScriptのarray.every(callbackFn)メソッドは、配列の全要素が指定された条件(コールバック関数)を満たしているかチェックし、すべて満たせばtrue、1つでも満たさなければfalseを返す便利なメソッドです。
空の配列に対しては常にtrueを返します。

()内の説明(引数)

every()のカッコ内には、各要素をテストする関数(コールバック関数)を渡します。

1. callbackFn (必須) 

配列の各要素に対して実行される関数です。この関数がtrue(真値)かfalse(偽値)を返すことで判定が行われます。

  • element: 現在処理されている配列の要素。
  • index (オプション): 現在処理されている要素のインデックス。
  • array (オプション): every()が呼び出された配列そのもの。

2. thisArg (オプション)

callbackFnを実行する際にthisとして使用する値です。

具体的な使用例

例:すべての数字が10より大きいかチェックする

例:1つでも条件に合わない場合

特徴

  • 途中停止: 条件を満たさない要素が見つかった時点で、残りの要素は処理されず、即座にfalseを返します。
  • 空配列[].every(...)trueを返します。
  • 読み方: “エブリ”と呼びます。

よく使われる関連メソッド

  • some(): 1つでも条件を満たすかチェックする(1つでも真ならtrue)。
  • filter(): 条件を満たす要素だけを抽出する。
  • map(): すべての要素を変換する

配列.some()

「内部配列(子配列)の少なくとも1つが条件を満たしているか」をチェックし、trueかfalseを返す効果があります。1つでも条件に合致する子配列を見つけた時点で即座に処理を終了(ショートサーキット)するため、効率的に検索が可能です

1. 二次元配列.some()の動作原理

二次元配列において、.some()は親配列の要素である「子配列」を順番にコールバック関数へ渡します。

2. 主な活用事例

① 2次元配列内の特定の要素の存在確認

「いずれかの行(子配列)に、特定の要素が含まれているか」のチェックに最適です。

② 2次元配列内での条件判定

「特定の条件を満たす行が、1つでも存在するか」を判定します。

3. 特徴と注意点

  • 戻り値: 条件に合致する要素が1つでもあればtrue、なければfalse
  • 高速性: 条件に合致した時点で走査をストップするため、大きな配列でも不要なループが省略されます。
  • 空の配列: 空の配列に対して実行すると、必ずfalseを返します。

二次元配列のすべての要素が条件を満たすかを確認したい場合は、.some()の代わりに.every()メソッドを使用します。

reduce()

配列の全要素にコールバック関数を適用し、最終的に単一の累積値(数値、文字列、オブジェクトなど)を返す高機能な配列操作メソッドです。配列を左から右へ順に処理し、合計算出、データ集計、配列からオブジェクトの生成など、複雑なデータを変換・圧縮する際に効果的です。

reduceメソッドの主な効果・用途

  • 配列の合計値・積の計算: 配列内の数値をすべて合計する際、最もシンプルに記述できます。
  • データの集計・グループ化: オブジェクトの配列から、特定のプロパティ(カテゴリー等)ごとに合計値や配列を作成できます。
  • 配列から別のデータ構造の生成: 配列を元に、新しいオブジェクトや連想配列を作成する際、mapやfilterを組み合わせるよりも効率的です。
  • 高度なデータ変換: データ構造を複雑に変換する際、一度のループで処理を完結させることができます

基本的な構文

accumulator (累積値): コールバックの戻り値を累積していく値。
currentValue (現在の値): 現在処理されている配列の要素。
initialValue (初期値): 最初にaccumulatorに渡す値(設定が推奨されます

具体的な利用例

1. 数値の合計

2. オブジェクトの集計

reduceを活用することで、ループ処理を記述することなく、より関数型プログラミングスタイルで簡潔に配列を処理できます。

new Set()

「重複しない値の集まり(集合)」を作るためのオブジェクトです。
配列(Array)に似ていますが、「同じ値は一つしか持てない」という点が最大の特徴です。

主な効果と使い道は以下の通りです。

1. 配列から重複を排除する 

配列を Set に渡し、再び配列に戻すだけで、重複要素を簡単に削除できます。

2. 値の存在チェックが高速(パフォーマンス向上)

配列の includes() は要素数が増えるほど時間がかかります(線形探索)が、Set の has() メソッドは、内部的に最適化されているため、非常に高速に値を検索できます。
大量のデータから特定の値があるか何度も確認する処理に向いています。

3. 「一意なデータ」であることを明示できる

コード内で Set を使うことで、後から読む人に対して「このデータ群に重複は存在しない」という意図を明確に伝えることができます。

4. 集合演算(和・積・差)が標準で可能

最新のブラウザ環境では、2つの Set 同士を比較して、共通部分(積集合)や差分(差集合)を求めるメソッド(例: intersection()difference() など)が標準で利用可能です。

基本的な使い方

  • 作成const mySet = new Set();
  • 追加mySet.add(値);(既にある値なら無視される)
  • 確認mySet.has(値);(あれば true
  • 削除mySet.delete(値);
  • 個数mySet.size;(配列の length に相当)

これは二次元配列にも使用できますか?

二次元配列(配列の中に配列がある状態)に対しても new Set() を使うことはできますが、期待通りに「中身が同じ配列」を重複として削除することはそのままではできません

理由は、JavaScript の Set が「値」ではなく、メモリ上の「参照(アドレス)」で重複を判断するからです

なぜうまくいかないのか?

たとえ中身が同じ [1, 2] であっても、プログラム上ではそれぞれ「別の箱(参照)」として扱われます

二次元配列の重複を削除する方法

二次元配列で「中身が同じもの」を除外したい場合は、一度データを文字列化して比較するのが一般的です。

方法1:JSON.stringify を使う(簡単・確実)

一度 JSON.stringify() で文字列("[1, 2]")に変換して Set にかけ、最後に JSON.parse() で配列に戻します

方法2:filter と join を使う(数値や単純な文字列のみの場合)

中身が単純な数値などの場合、join() でカンマ区切りの文字列にして判別することも可能です

まとめ

  • そのまま使う: 同じ「インスタンス(変数)」なら重複排除されるが、中身が同じだけの別配列は排除されない
  • 解決策map(JSON.stringify) で一度文字列にしてから Set に入れる。

コメント

タイトルとURLをコピーしました