JavaScript インタビュー: 配列の平坦化メソッドを実装する方法

JavaScript インタビュー: 配列の平坦化メソッドを実装する方法

1 配列のフラット化とは何ですか?

概念は単純で、「多次元」配列の次元を減らすことを意味します。たとえば、次のようになります。

// 元の配列は「3次元」配列です。const array = [1, 2, [3, 4, [5, 6], 7], 8, 9]
 
// 2次元に縮小できます newArray1 = [1, 2, 3, 4, [5, 6], 7, 8, 9]
 
// 1次元に縮小することもできます newArray2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

配列の平坦化は、配列の平坦化や配列の次元削減とも呼ばれます。

2 JS標準ライブラリの配列フラット化メソッド

JavaScript標準ライブラリは配列を平坦化するメソッドArray.prototype.flat()を実装しています。

flat() メソッドは、配列を指定された深さまで再帰的に走査し、走査されたサブ配列内のすべての要素を新しい配列にマージして返します。

構文: var newArray = arr.flat([depth])

パラメータ: depth はオプションの値で、走査する多次元配列の深さを示します。デフォルト値は 1 です。これは、拡張(または次元を縮小)するレイヤーの数として理解できます。

戻り値: 走査された要素とサブ配列の要素で構成される新しい配列

例:

定数配列 = [1, 2, [3, 4, [5, 6], 7], 8, 9]
const newArray1 = array.flat() // array.flat(1) と同等。1 次元減らす // newArray1: [1, 2, 3, 4, [ 5, 6 ], 7, 8, 9]
 
const newArray2 = array.flat(2) // 2次元を削減 // newArray2: [1, 2, 3, 4, 5, 6, 7, 8, 9]

特別:

深さ<=0の場合、返される配列は元の配列と同じ次元を持ちます(次元のみが同じであることに注意してください。空きスペースについてはポイント3を参照してください)。

定数配列 = [1, 2, [3, 4, [5, 6], 7], 8, 9]
配列.flat(-1)
// [1, 2, [3, 4, [5, 6], 7], 8, 9]

深さ=Infinityの場合、返される配列は1次元になります

配列.flat(無限大)
// [1、2、3、4、5、6、7、8、9]

元の配列に空がある場合、flat メソッドはそれを削除します。flat(0) でも空は削除されますので、1 つ目のポイントは「次元数だけが同じである」ということです。そして、平面方式が拡張したレベルでは空きスペースが解消され、より深いレベルの空きスペースは解消されません。

定数配列1 = [1, , 2, [3, ,4, [5, 6], 7], 8, 9] 
// この配列には2つの空きスペースがあることに注意してください array.flat(0)
// [ 1, 2, [ 3, ,4, [ 5, 6 ], 7 ], 8, 9 ]
// 最初の空きはなくなったが、2番目の空きはまだある

3 フラットメソッドの実装

1つのレイヤーを拡張する(1つの次元を減らす)フラットメソッドの手順は次のとおりです。配列を走査し、現在の要素が配列であるかどうかを判断します。配列でない場合は直接保存します。配列の場合は、展開して保存します。

flat メソッドは、1 つのレイヤーの拡張に基づいて、配列のサブ要素に対して同じ操作を再帰的に実行することにより、複数のレイヤーを拡張します (複数の次元を削減します)。

この方法は、次の 3 つのステップに分けられます。

1. 配列を走査する方法

2. 要素が配列であるかどうかを判断する方法

3. 再帰

上記の3つのステップを実装し、それらを組み合わせてさまざまなフラット実装を取得します。

3.1 配列を走査する方法

方法は多数ありますが、ここでは 3 つのカテゴリを紹介します。

1. 関連

  • forループ
  • ...のために

for...in はオブジェクトのプロパティを反復処理するために構築されており、配列での使用は推奨されません。

定数配列 = [1, 2, [3, 4, [5, 6], 7], 8, 9]
// for ループ for (let i = 0; i < array.length; i++) {
    const要素 = 配列[i];
}
// 〜の〜
for (配列のconst要素) {
    
}

2. 配列メソッド:配列要素を直接取得できるメソッド

  • 各()
  • 減らす()
  • 地図()
// 各()
配列.forEach(要素 => {
    
});
// 減らす()
配列.reduce((pre, cur) => {
    const 要素 = cur
}, [])
// マップ()
配列.map(要素 => {
  
})

3. 配列メソッド: イテレータオブジェクトを返すメソッド

  • キー()
  • 値()
  • エントリ()
// これら 3 つのメソッドは、トラバーサル オブジェクトを取得するためだけのものであり、トラバーサルを行うには for...of と一緒に使用する必要があります // keys()
for (let i of array.keys()) {
  const 要素 = 配列[i]
}
// 値()
for (let 配列の要素.values() ) {
  
}
// エントリ()
for (let [i, 要素] of array.entries()) {
  コンソール.log(配列[i])
  console.log(要素)
}

3.2 要素が配列であるかどうかを判断する方法

変数 a があると仮定し、それが配列かどうかを判断します。 4つの方法があります:

  • 配列には、変数が配列であるかどうかを判断するために使用される静的メソッド Array.isArray() があります。
  • instanceof 演算子は、コンストラクター関数のプロトタイプ プロパティがインスタンス オブジェクトのプロトタイプ チェーンに出現するかどうかを検出するために使用されます。
    が配列の場合、Array.prototype がそのプロトタイプ チェーンに表示されます。
  • オブジェクトのコンストラクタによって決定されます (コンストラクタは手動で変更できるため、このメソッドは失敗する可能性があります)
  • Object.prototype.toString()から判断すると、このメソッドはオブジェクトを表す文字列を返すことができる。
// 方法 1
配列.isArray(a)
// 方法 2
配列のインスタンス
// 方法 3
a.コンストラクタ === 配列
// 方法 4
// call を使用して Object.prototype の toString メソッドを呼び出します。Object.prototype.toString.call(a) === '[object Array]'
 
// この toString はすでに Object.prototype.toString を上書きしているため、判断できません
// Object.prototype.toString のみが正しく型を判別できます a.toString()

3.3 再帰

再帰: 子要素に対して同じ操作を実行する

関数flat() {
  res = [] とします
  配列を走査する {
    if (現在の要素が配列の場合) {
      flat(現在の要素)は1次元配列を取得し、その1次元配列をresに連結します} else {
      res.push(現在の要素)
    }
  }
  戻り値
}

3.4 フラットメソッドの予備実装

トラバーサル方式と配列判定方式を選択することで、次のように再帰によるフラット方式を事前に実装できます。

関数 myFlat(arr) {
  res = [] とします。
  for (arrのconst項目) {
    Array.isArray(item) の場合 {
      res = res.concat(myFlat(item));
      // concat メソッドは新しい配列を返し、元の配列を変更しないことに注意してください} else {
      res.push(アイテム);
    }
  }
  res を返します。
}

myFlat メソッドは、多次元配列を 1 次元配列に平坦化できますが、拡張の深さを指定することはできず、空の配列を処理することもできません。

4 最適化

4.1 拡張深さの指定

拡張深度を処理するのは実際には非常に簡単です。再帰終了条件、つまり depth<=0 を追加できます。コードは次のとおりです。

関数 myFlat(arr, 深さ = 1) {
  // 深さ <= 0 の場合は直接戻ります if (depth <= 0) {
      リターン
  }
  res = [] とします。
  for (arrのconst項目) {
    Array.isArray(item) の場合 {
      // 再帰呼び出しごとに深さが1ずつ増加します
      res = res.concat(myFlat(item, depth - 1));
    } それ以外 {
      res.push(アイテム);
    }
  }
  res を返します。
}

4.2 アレイの空き領域の処理

実際、空の配列は避けるべきです。

先ほど、配列を走査するさまざまな方法について説明しましたが、配列内の空の位置の処理方法はそれぞれ異なります。

ForEach、reduce、map は走査時に空白を無視しますが、for...of は空白を無視せず、未定義として扱います。

4.2.1 for...ofは空白の判断を追加する

したがって、for...of で配列を走査する myFlat メソッドを改善する必要があります。

関数 myFlat(arr, 深さ = 1) {
  深さ<= 0の場合{
    arr を返します。
  }
  res = [] とします。
  for (arrのconst項目) {
    Array.isArray(item) の場合 {
      res = res.concat(myFlat(item, depth - 1));
    } それ以外 {
      // 配列が空かどうかを判断します。item !== undefined && res.push(item);
    }
  }
  res を返します。
}

4.2.2 forEach と map メソッドのトラバーサル

もちろん、forEach メソッドや map メソッドを使用して配列を走査することもできるので、手動で判断する必要はありません。

しかし、考慮すべき特別なケースがあります。つまり、depth <= 0 の場合、フィルター メソッドを使用して配列の空き領域を削除します。

// 各
関数 myFlat(arr, 深さ = 1) {
  深さ<= 0の場合{
    arr.filter(item => item !== undefined) を返します。
  }
  res = [] とします。
  arr.forEach((アイテム) => {
    Array.isArray(item) の場合 {
      res = res.concat(myFlat(item, depth - 1));
    } それ以外 {
      res.push(アイテム);
    }
  });
  res を返します。
}
 
// マップ
関数 myFlat(arr, 深さ = 1) {
  深さ<= 0の場合{
    arr.filter(item => item !== undefined) を返します。
  }
  res = [] とします。
  arr.map((アイテム) => {
    Array.isArray(item) の場合 {
      res = res.concat(myFlat(item, depth - 1));
    } それ以外 {
      res.push(アイテム);
    }
  });
  res を返します。
}

4.2.3 削減法

その中でもreduceメソッドは最も簡潔であり、面接でよくテストされるメソッドの1つでもあります。

関数 myFlat(arr, 深さ = 1) {
  深さ > 0 を返す
    ? arr.reduce() 関数
        (前、現在) =>
          pre.concat(Array.isArray(cur) ? myFlat(cur, depth - 1) : cur),
        []
      )
    : arr.filter((item) => item !== 未定義);
}

5 その他

5.1 スタック

理論的には、再帰メソッドは通常、スタックを使用して非再帰メソッドに変換できます。

関数 myFlat(arr) {
  res = [] とします。
  const スタック = [].concat(arr);
  スタックの長さが0より大きい場合
    定数項目 = stack.pop();
    Array.isArray(item) の場合 {
      // スプレッド演算子を使用して 1 つのレイヤーを展開します。stack.push(...item);
    } それ以外 {
      項目 !== 未定義 && res.unshift(item);
    }
  }
  res を返します。
}

ただし、この方法では拡張の深さを指定できず、1 次元配列にのみ完全に拡張できます。

5.2 改善点

スタックが拡張深度を指定できないという欠点を改善するためのコードは次のようになります。

関数 myFlat(arr, 深さ = 1) {
  深さ<= 0の場合{
    arr.filter((item) => item !== undefined) を返します。
  }
  解決しましょう;
  キューを [].concat(arr);
  (深さ > 0)の間{
    解像度 = [];
    キュー.forEach((アイテム) => {
      Array.isArray(item) の場合 {
        // スプレッド演算子を使用して配列を展開する前に、フィルター メソッドを使用して空のスペースを削除することに注意してください res.push(...item.filter((e) => e !== undefined));
      } それ以外 {
        res.push(アイテム);
      }
    });
    深さ - ;
    キュー = res;
  }
  res を返します。
}

要約する

JavaScript 面接で配列のフラット化を実装する方法についての記事はこれで終わりです。JS で配列のフラット化を実装する方法の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JS配列重複排除の詳細
  • JavaScript配列の重複排除のいくつかの方法についての詳細な説明
  • JavaScript 配列重複排除問題の詳細な研究
  • JavaScript 配列重複排除ソリューション
  • jsは配列の平坦化を実装します
  • JavaScript データのフラット化の詳細な説明
  • 配列をフラット化する 5 つの JavaScript の方法
  • JavaScript 配列の重複排除とフラット化関数の紹介

<<:  Dockerコンテナにホストディレクトリへの書き込み権限がない場合の解決策

>>:  チェックボックスとラジオボタンの配置を実装する方法

推薦する

CentOS7 (YUM) での MySQL 5.7 のインストールと設定のチュートリアル

インストール環境: CentOS7 64ビット、MySQL5.7 1. YUMソースを設定するMyS...

Centos7 での NFS サービス構築の紹介

目次1. サーバー2. クライアント3. テストサービス1. サーバー1. YUMソースを使用してN...

W3C チュートリアル (12): W3C SOAP アクティビティ

Web サービスは、アプリケーション間の通信に関係しています。SOAP は、Web サービス間の X...

JavaScript の便利な配列トリック 12 選

目次アレイ重複排除1. from() を新しい Set() メソッドに重ねる2. スプレッド演算子 ...

Linux環境変数の設定に関する完全なガイド

Linux環境変数の設定ソフトウェアのインストールをカスタマイズする場合、多くの場合、環境変数を設定...

CSSの複数条件の書き方の詳細説明:

:not疑似クラスセレクターは、式に一致しない要素をフィルタリングできます。例 テーブル tbod...

jQuery はピッカーをシミュレートしてスライド選択効果を実現します

この記事では、スライド選択効果を実現するピッカーをシミュレートするjQueryの具体的なコードを参考...

WordPress実験を実装するための3つの仮想マシンのKVM展開の詳細説明

1. KVM の概要カーネルベースの仮想マシンの略称は、Linux 2.6.20 以降のすべての主要...

MySQL 8.0.19 では、間違ったパスワードを 3 回入力するとアカウントがロックされるようになりました (例)

MySQL 8.0.19 では、間違ったパスワードを 3 回入力するとアカウントがロックされるよう...

Nginxリバースプロキシ設定でプレフィックスが削除される

nginx をリバース プロキシとして使用する場合、リクエストをそのまま次のサービスに転送するだけで...

ナビゲーションデザインと情報アーキテクチャ

<br />ナビゲーションについて話すときは、ほとんどの場合、ナビゲーションがコンテンツ...

Vueのprovideとinjectの使い方と原則を分析する

まず、provide/inject を使用する理由について説明しましょう。祖父コンポーネントと孫コン...

Alibaba Cloud Centos7のインストールとSVNの設定

1. SVNサーバーをインストールする yum でサブバージョンをインストール2. SVNバージョン...

Debian 9 システムに MySQL データベースをインストールする方法

序文タイトルを見ると、誰もが「Debian 9 に MySQL をインストールするにはどうすればいい...

キャンバスはスクラッチカード効果を描画します

この記事では、キャンバスでスクラッチカード効果を描画するための具体的なコードを参考までに共有します。...