はじめに
私は思考トレーニングの一環として、LeetCodeを解く過程における思考の軌跡をアウトプットしています。
今回は、JavaScriptを使って「2724. Sort By」の問題を解いた軌跡を記録していきます。
問題URL:
https://leetcode.com/problems/sort-by/description/
問題の概要
- 解くのにかかった時間:10分+15分+5分+15分
この問題を一言で言うと
出力に伴って昇順で並び替えた値を格納した配列を返す問題
入力(Input)・出力(Output)
ケース1:
入力(Input):
arr = [{"x": 1}, {"x": 0}, {"x": -1}], fn = (d) => d.x
出力(Output):
[{"x": -1}, {"x": 0}, {"x": 1}]
説明:配列内にあるオブジェクトの左側(キー)に対応した値(value)を返す
ケース2:
入力(Input):
arr = [[3, 4], [5, 2], [10, 1]], fn = (x) => x[1]
出力(Output):
[[10, 1], [5, 2], [3, 4]]
説明:配列のインデックスが1(今回なら4,2,1の右側の値)の値を対象として昇順(小さい順から大きい順)に並び替える
条件
- 2つの引数(arr,fn)のうち、fnは与えられた配列に対して重複する数値を返さない
- fnは数値のみを返す
- fnの数値によって最終的に返す配列のソート順が決まる
分からなかったことを仮説・調査を通して整理する
①fnの数値によって最終的に返す配列のソート順が決まる
仮説:fnは数値が入る事は分かったので、以下のconsole.logでfnにどういった値が入るかを確認した後にそれぞれのケースに沿った実装をしていく
console.log('fn===', fn);
調査結果:
それぞれのfnに[Function (anonymous)]が出力された
②[Function (anonymous)]はどういう意味?
仮説:anonymousは無名などの意味を持つので、そもそもconsole.logでfnを値を確認する事自体が間違っている
調査結果:
- [Function (anonymous)]:プログラミングにおいて「名前のついていない関数(いわゆる無名関数)」意味を持つ
- 仮説通り、そもそもコンソールログで確認する事自体が間違っているみたい
- 分かったこととして、fnの数値自体は一旦置いていてarrの配列をどうソートするかを考えた方が良さそう
不要だった思考・遠回りした部分
- if文による冗長的なコーディング
- 当初はif (fn.toString() == '(x) => x[1]') ~~~のように一つずつfnの値をif文で条件定義していた。当然それで問題を解けるはずもなく、最終的にソートの汎用的なコードを検索して提出しました
- 最終的な実装は以下の通りになっていますが、これを自力で思いつけなかったのが反省点となります
最終的な実装
実際の回答コード
/**
* @param {Array} arr
* @param {Function} fn
* @return {Array}
*/
var sortBy = function(arr, fn) {
return arr.sort((a, b) => fn(a) - fn(b));
};
振り返り
なぜ上記の実装で問題を解くことが出来るのか?
- まず今回の問題のポイントは配列の要素(arr)を比較するのではなく、fnを通した結果を比較する点にあります
- JavaScriptの
sort()は、配列の中から2つの要素を取り出して、「どちらを前に置く?」かを判断してくれます - この判断を応用することで、fn(a)とfn(b)の2つの要素から比べたい数字を取り出すことができます
-
fn(a) - fn(b)で計算すると、どちらの数字が小さいのかを簡単に判断できます- マイナスの場合:aを前にする
- プラスの場合:bを前にする
- つまり、2つの値を取り出す→fnを参照して比べたい数値を取り出す→小さい方から前に置いていくの3ステップを1行で解決しているのが今回の問題の回答コードとなります
気づき・感想
- こういったアルゴリズム的思考は、普段生きているだけでは思いつかないので、こういう風に練習を重ねて思考の柔軟性を高めていくのが自分には合っていると感じました
- どれだけポジティブに考えても、自分が天才プログラマーである可能性は間違いなく0なので、その分天才と言われている方々の思考法を練習で身につけて自分自身の思考を研ぎ澄ましていくべきだと改めて考えました