185
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【挑戦状の正解発表&解説】配列の要素を増やすには?〜面白解答も紹介〜

Last updated at Posted at 2022-08-22

先日、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

剰余演算子%)を使う感じですね。

n2で割った余り」を求めるということです。

  • n2で割った余り
    • 1であれば、n奇数
    • 0であれば、n偶数

という感じです。

n % 2の結果は、10のどちらかになります。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のプレイグラウンドを用意してありますので、
よかったら挑戦してみてください。

そして面白解答が思い浮かんだら教えてください・・・笑

新しい記事もよろしくやで!

185
57
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
185
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?