先日、Twitter上でこんなクイズを出題しました
↓こちらです。
この記事では、クイズの正解発表をして行きます。
クイズの内容
クイズの内容は以下です。
【JSクイズ】
/* ここに回答を書いてください */
の部分を埋めてくださいやで!
const array1 = [1, 2, 3, 4, 5, 6]
const array2 = array1./* ここに解答を書いてください */
console.log(array2)
// -> [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6]
要は、
[1, 2, 3, 4, 5, 6]
という配列から
[1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6]
という配列を生成するには
どうすればいいのか?
という問題です。
もう少し要約すると、
array1
という配列の各要素をチェックして、
奇数なら3つに増やすべし!
偶数なら2つに増やすべし!
そしてarray2
という変数に格納すべし!
↑こんな問題です。
正解発表
それでは正解を発表いたします。
いろんな書き方がありますが、私が想定していた模範解答は以下です。
const array2 = array1.flatMap(n => n % 2 ? [n, n, n] : [n, n])
flatMap()
というメソッドを見たことがない方は「なんやこれ?」と感じるかもしれません。
順を追って解説して行きます。
解説
まず、今回やりたいことは
array1
という配列の各要素をチェックして、
奇数なら3つに増やすべし!
偶数なら2つに増やすべし!
そしてarray2
という変数に格納すべし!
↑こうでしたね。
「array1
という配列をもとに、array2
という配列を作る」必要があります。
ということは、map()
メソッドが使えそうですね。
map()
メソッドを使って、
とりあえず、配列の全ての要素を2つに増やしてみましょう。
const array2 = array1.map(n => [n, n])
↑配列内の各要素を、全て2個入りの配列にしてあげる感じです。
すると、出力結果は以下のようになります。
console.log(array2)
// => [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6]]
↑当然、二重の配列になってしまいます。
なので、最後にflat()
してあげます。
const array2 = array1.map(n => [n, n]).flat() // <- .flat() 追加!
↑こうですね。
すると、出力結果は以下のようになります。
console.log(array2)
// => [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6]
↑二重の配列を、フラットな配列にすることができました。
結果として、全ての要素を2個に増やすことができました。
flatMap()
メソッドを使ってみよう
上記のように
map()
してからflat()
したい
そんなときにflatMap()
メソッドが使えます。
const array2 = array1.flatMap(n => [n, n])
console.log(array2)
// => [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6]
↑こうですね。
つまりflatMap()
メソッドとは
n => [n, n]
↑このような関数を渡すことで、
配列の要素を増やすことができるメソッドと言えます。
ちなみに
flatMap()
メソッドに対して、
n => []
↑こういう関数を渡せば、要素を減らす(取り除く)こともできます。
クイズ解説の続き
const array2 = array1.flatMap(n => [n, n])
console.log(array2)
// => [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6]
とりあえず、配列の要素を全部2個に増やすことができました。
あとは、
奇数なら3つに増やすべし!
偶数なら2つに増やすべし!
↑この条件分岐が必要ですね。
「奇数なのか偶数なのか」を調べるには、以下の式を使います。
n % 2
剰余演算子(%
)を使う感じですね。
「n
を2
で割った余り」を求めるということです。
-
n
を2
で割った余りが-
1
であれば、n
は奇数 -
0
であれば、n
は偶数
-
という感じです。
※n % 2
の結果は、1
か0
のどちらかになります。2
とか5
とかにはなりません。(当たり前か)
コードにすると、
if (n % 2 === 1) {
// 奇数の場合の処理
} else {
// 偶数の場合の処理
}
↑こんな風に書けそうですね。
条件に応じて、配列の要素を増やすべし
先ほどは、flatMap()
メソッドに対して、
n => [n, n]
↑この関数を渡すことで、配列の各要素を2個ずつに増やすことができました。
ここに「奇数かどうか」という条件を加えたいので・・・
n => {
if (n % 2 === 1) {
// 奇数だったら3つ!
return [n, n, n]
} else {
// 偶数だったら2つ!
return [n, n]
}
}
↑こんな関数を書いてみます。
この関数をflatMap()
メソッドに渡してあげれば、
奇数なら3つに増やすべし!
偶数なら2つに増やすべし!
↑この条件を満たせそうです。
三項演算子を使って、1行で書くと・・・
n => n % 2 === 1 ? [n, n, n] : [n, n]
↑こうですね。
n % 2 === 1
という条件は、
今回の場合n % 2
と書いても大丈夫なので、
n => n % 2 ? [n, n, n] : [n, n]
↑これでもOKです。
では、この関数をflatMap()
メソッドに渡してみましょう。
const array1 = [1, 2, 3, 4, 5, 6]
const array2 = array1.flatMap(n => n % 2 ? [n, n, n] : [n, n])
console.log(array2)
// -> [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6]
出力したかった内容を、無事に出力することができました。
模範解答の解説は以上です。
別解
こんな解答をしてくださった方もいました。
メインの処理としては、
const array2 = array1.flatMap((x) => Array(x % 2 + 2).fill(x))
↑こうですね。
flatMap()
メソッドに対して
(x) => Array(x % 2 + 2).fill(x)
↑こんな関数を渡しています。
x % 2 + 2
という式がスマートで「頭いいな〜!」と思いました。
-
x % 2
は-
x
が奇数であれば1
になる -
x
が偶数であれば0
になる
-
↑この法則を利用して、
そこに2
を足してやることで
-
x % 2 + 2
は-
x
が奇数であれば3
になる -
x
が偶数であれば2
になる
-
↑こういうことをやってるわけですね・・・!
つまりArray(x % 2 + 2)
の部分は、
Array(3)
またはArray(2)
として機能するわけです。
そうやって、長さを指定した配列を生成して、
fill()
メソッドで埋めてあげる、と。
ワイじゃ一生思いつかへんわ・・・
ていうかArray()
ってnew
つけなくてもいいんですね・・・!
これも知りませんでした。
クイズ1問でこんなに勉強させてもらって、お得な気分・・・!
面白解答もたくさん
面白解答も沢山いただきました。
面白解答その1
メインの処理
const array2 = array1.concat(1, 1, 2, 3, 3, 4, 5, 5, 6).sort()
いやarray1
に足りない内容を足してsort()
すんのかい!
ちょっと強引な気もしますが、ルール上は正解ですね・・・!
面白解答その2
メインの処理
const array2 = array1.slice(6).concat([1,1,1,2,2,3,3,3,4,4,5,5,5,6,6]);
いやarray1
の要素たちの立場!
丸ごと入れ替わっとるやないかい!
っていうか、出力したい配列をベタ書きしとるやないかい!
でも、ルール上は正解ですね・・・!
面白解答その3
メインの処理
const array2 = array1.concat(array1, array1).reduce((a,b,c,d)=>
(d.push(...d.splice(Number(a%16n),1)),a >> 4n||d),4721443915042874085729n).slice(0, 15);
いや難読の極み!
でも、実行してみたら正解でした・・・!
さすが@uhyo大先生・・・!
面白解答その4
いやユーザーの判断で配列に追加すんのかい!
何回ボタン押さすねん!
っていうか、アルゴリズムを「運用でカバー」すな!
でも、正解っちゃ正解なのか・・・?
面白解答その5
メインの処理
const array2 = array1.length;const 待避 = console.log;console.log=function(){待避("[1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6]")}
いや一行に何文書くねん!
そしてconsole.log()
メソッドを上書きって!
でも「セミコロン禁止」ってルールに書いてなかったしなぁ。。。
正解ということになるのか・・・?
面白解答その6
メインの処理
const array2 = array1.unko || [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6]
いや頼むからarray1
の中身を使ってあげて!
(ワイ自身の解答ですが)
総括
最後は大喜利大会みたいになっていましたが、
数百名もの方々が解答してくださり、かなり盛り上がりました。
出題者である私自身も、
「え、こんな書き方もあるんかい!」
と、とても勉強になりました。
ご参加いただいた皆さま、ありがとうございました!
もしよかったらご挑戦ください
もしかすると、まだまだ他の解答もあるかも知れません。
TypeScriptのプレイグラウンドを用意してありますので、
よかったら挑戦してみてください。
そして面白解答が思い浮かんだら教えてください・・・笑