【JavaScript】ソートせずに配列から上位2つの要素(最大値トップ2)を1パスで取得する方法
JavaScriptには、並び順がバラバラの数値が格納された配列があります。ここでの課題は、この数値配列を受け取って、配列内で最も大きい2つの要素(上位2要素)だけを抽出し、新しい配列として返す関数を書くことです。
さらに重要な条件として、処理は1パス(ワンパス)で完了させる必要があります。つまり、forループは1回だけ使う、あるいはES6の配列メソッドを利用する場合も1回の呼び出しにとどめ、ネストした処理(二重ループなど)は避け、時間計算量をO(n) の線形時間に保たなければなりません。
解決策:Array.prototype.reduce() を使う
この問題は、Array.prototype.reduce() メソッドを使うとエレガントに解決できます。reduceの初期値として「負の無限大」を2つ持つ配列 [-Infinity, -Infinity] を用意し、各要素を走査しながら最大値と2番目に大きい値を順次更新していきます。
コード例
const arr = [23, 65, 67, 23, 2, 6, 87, 23, 45, 65, 3, 234, 3];
const topTwo = arr => {
// 要素が2つ未満の場合は false を返す
if(arr.length < 2){
return false;
};
return arr.reduce((acc, val) => {
// 現在の最大値より大きければ、入れ替えを行う
if(val > acc[0]){
let t = acc[0];
acc[0] = val;
acc[1] = t;
// 最大値以下でも2位より大きければ2位を更新
}else if(val > acc[1]){
acc[1] = val;
};
return acc;
}, [-Infinity, -Infinity]);
};
console.log(topTwo(arr));
実行結果
コンソールへの出力は次のようになります。
[ 234, 87 ]
仕組みの解説
アキュムレータ acc の acc[0] には常に「現時点での最大値」が、acc[1] には「2番目に大きい値」が保持されます。
- 走査中の値
valがacc[0]より大きい場合:旧最大値を2位へ退避させ、valを新しい最大値とします。 valが最大値以下だがacc[1]より大きい場合:acc[1]だけを更新します。
初期値に -Infinity を使うことで、負の数を含むあらゆる数値配列にも正しく対応できます。また、配列を一度だけ走査するため、計算量はO(n)、追加のメモリも定数領域で済み、非常に効率的な実装となっています。
-
【初心者向け】JavaScriptのArray.from()メソッドの使い方を実例で解説
JavaScript の Array.from() メソッドは、length プロパティを持つオブジェクト(配列風オブジェクト)や、文字列・Map・Set などの反復可能(イテラブル)なオブジェクトから、新しい Array オブジェクトを生成して返すためのメソッドです。元のオブジェクトは変更されず、常に新しい配列インスタンスが返されます。 基本構文 Array.from(obj, mapFunction, val) パラメータの説明 obj:配列へ変換したい対象のオブジェクト。配列風オブジェクト(length プロパティを持つもの)や反復可能なオブジェクトを指定します。 mapFunctio
-
JavaScriptのArray.from()メソッドとは?使い方と実例をわかりやすく解説
Array.from()メソッドは、配列風オブジェクト(array-like)や反復可能オブジェクト(iterable)から、新しい配列オブジェクトを作成するための便利なメソッドです。文字列、Map、Set、NodeListなど、さまざまなデータを手軽に配列へ変換できます。 Array.from()の基本的な動作 例えば、文字列「HelloWorld」に対してArray.from()を使用すると、1文字ずつ分割された新しい配列が生成されます。以下に実際のコード例を示します。 サンプルコード <!DOCTYPE html> <html lang="ja"&g