結論
- プログラミングクイズでよく使う記法と知見をメモしています。
- 初〜中級者向けの内容です。
- 手短に結論だけ欲しい方は、各タイトルの見出し〜ソースまでをお読みいただければ十分です。
はじめに
プログラミングのクイズを200問解いてみました。
難易度は文を読む時間を含めて1分〜3分ほどで解ける簡単な問題が多かったですが、解き方を調べるうちに
「 こうしたら短く書けるんだ! 」 とか、
「 この関数、こんな使い方できたんだ・・・ 」
などといった気づきを得ました。
基本的な文法も改めて学習することができて非常に有意義でした。
その時の知見をここにメモしようと思います。
けっこう好みがわかれる書き方もしてると思います。
暇つぶし感覚で読んでみてください。
1.console.log(値1,値2)
console.log()
にカンマ区切りで複数の値を渡すと、記述した順番通りにスペース区切りで値を出力してくれます。
const month = 6;
const date = 27;
console.log(month, date);
// 6 27
console.log(month, '/', date);
// 6 / 27
一応、MDNを読んでみました。
カンマ区切りで渡した値を出力する旨がきちんと書いてありました。
console.log(obj1 [, obj2, ..., objN]);
obj1 ... objN
出力する JavaScript オブジェクトのリスト。
各オブジェクトの文字列表現が記述順で出力されます。
MDN -console.log-
これを知るまでは複数の値を出力する際は 変数1 + " " + 変数2
としたり、テンプレート文字${変数1} {変数2}
列を使っていましたが、どう頑張ってもカンマで区切るのが一番楽です!
この書き方は超常識なのかもしれませんが、今まで読んだJavaScriptの学習教材には出てきませんでした。もっと早く知りたかった・・・。
2. 配列.map(Number)
配列.map(Number)
とすると、配列内の要素をすべてNumberオブジェクトに変換できます。
['1','2','3'].map(Number)
// [ 1, 2, 3 ]
配列内の要素がNumberオブジェクトにできない値であれば、NaN
が設定されます。
['1', 'a', '3'].map(Number)
// [ 1, NaN, 3 ]
map
といえばarr.map(x => x * 2);
のように引数を受け取って処理したものを返す使い方しか知らなかったのですが、Numberを渡すだけで処理してくれるみたいです。
余談: .map(parseInt)
について
.map(Number)
と同じ要領でparseIntを使ってもNumberオブジェクトになりそうですが・・・そうはなりません。parseIntをそのまま渡すと思わぬ結果が返ってくるので注意してください。
["1", "2", "3"].map(parseInt);
// [1, NaN, NaN]
parseInt
は引数を2つとるため、このような結果になります。
以下のように、引数を1つだと明示すれば想定通りの結果が得られます。
['1', '2', '3'].map((str) => parseInt(str));
// [ 1, 2, 3 ]
詳しくはMDNにわかりやくす書いてあるのでそちらを参照してください。
MDN - Array.prototype.map() トリッキーな使用例-
3. 配列.map(Math.メソッド)
配列.map(Math.メソッド)
とすると、配列内の要素すべてに渡したメソッドを実行してくれます。
例えば小数点以下を切り捨てて整数にしてくれるMath.floor
を渡すと・・・
[1.1, '2.2', 3.3].map(Math.floor)
// [1, 2, 3];
きちんと計算した配列を生成します。
こちらはStringオブジェクトでも数字であればよしなにNumberとして扱ってくれます。
4.[,変数名] = 配列
分割代入で[,変数名] = 配列
とすると、不必要な値を定義せずに無視することができます。
例えば[, str] = ['a', 'b']
とすると、配列の0番目の要素('a'
)を無視し、配列1番目の要素('b'
)のみ左辺の変数(str
)に格納されます。
const [, str] = ['a', 'b'];
console.log(str);
// b
これは何番目に何の値が入っているのかがわかりきっている場合によく使います。
例えば日時情報などです。
String(new Date()).split(' ')
には日付や時間などの情報がたくさん入っています。
String(new Date()).split(' ')
// [ 'Fri', 'Jun', '26', '2020', '29:39:55', 'GMT+0900', '(GMT+09:00)' ]
ここから時間だけを取り出したい場合、const [, , , , time]
に代入します。
const [, , , , time] = String(new Date()).split(' ');
console.log(time);
// 19:39:55
このように欲しい変数だけを定義すると、コードの見通しがよくなるのでオススメです。
詳しくはこちらを参照してください。
MDN -分割代入 返値の無視-
余談: 残余パターン(...arr
)との併用について
この書き方は残余パターンと併用して使うことが結構ありました。
例えば[人数, 値1, 値2, 値3 ・・・]
という入力から、値1以降を変数に格納する場合は以下のように書きます。
const [, ...arr] = ['人数', '値1', '値2', '値3'];
console.log(arr);
// [ '値1', '値2', '値3' ]
ちなみにこれはslice()
を使っても同じ結果が得られますが・・・
const arr = ['人数', '値1', '値2', '値3'].slice(1);
console.log(arr);
// [ '値1', '値2', '値3' ]
slice()
は文の末尾に出てくるので、そこまで読まないとどこで値を区切るのかがわかりません。
その点分割代入なら、変数定義の時点で「いらない要素があるのか」とすぐに察することができるので、個人的にはこっちの方が好きです。
5. .sort()
sort()
は最後に結果を出力する際によく使いますが、ちょっと注意が必要です。
文字列の配列に.sort()
を使うと、辞書順に良い感じに並べ替えてくれます。
['banana', 'orange', 'apple'].sort()
// [ 'apple', 'banana', 'orange' ]
しかし数値に使うと思わぬ結果になります。
console.log([34, 115, 86, 205, 76, 21].sort());
// [115, 205, 21, 34, 76, 86];
数値でも文字列として比較されるため、このような結果になります。
通ったり通らなかったりするので、原因がわからず悩むことになります。。😭
数値の並び替えは以下のようにしましょう。
[34, 115, 86, 205, 76, 21].sort((a, b) => a - b))
// [ 21, 34, 76, 86, 115, 205 ]
関連記事:
余談: ほかのメソッドと組み合わせる
sort()
と他のメソッドを同時に扱うことがよくあります。
例えば「スコア上位TOP3を出力せよ」という問題がよく出てくるのですが、以下のように書くことができます。
const scores = [34, 54, 115, 86, 45, 76, 131];
scores
.sort((a, b) => a - b) // 小さい順に並び替え
.reverse() // 反転して大きい順にする
.slice(0, 3) // 最初の3つだけ取り出す
.forEach((num) => console.log(num)); // 1つずつ出力する
// 131
// 115
// 86
関数を組みわせて特定の位置から欲しい値を取りたい時にも便利です。
ただし、最終的な出力なら気にしなくてOKですが、sort()
は破壊的メソッドなので、扱いには注意してください。
関連記事:
まとめ
私が取り組んでいたクイズ問題の入力値は、数値なのにStringやスペース区切りの文字列として渡ってくることがほとんどでした・・・。
それを200問解いたら、文字列や配列を操作するお決まり文をスラスラ書けるようになりました。
また、最適な書き方を追求する過程で、この記事に書いたような注意点や良い記法があることを学べました。
知見はまだあるような気がするので、思い出したら追記しようと思います。
(前に全く同じ記事を投稿してましたが、そちらは間違えて消してしまいました。。ストックしていただいてた方、すみません。。)