give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)

はじめに:「初心者は何をアウトプットすればいいの?」問題について

以前から何度か書いているのですが、Ruby初心者の方で「Rubyの勉強を始めました!アウトプットがんばります!」と言いつつ、実際はアウトプットしているのは、ほとんど書籍や他のサイトに書かれている内容を右から左へ丸写ししただけ、という方をよく見かけます。

その話題については、以下の記事で詳しくまとめているので、興味がある方はこちらをご覧ください。

blog.jnito.com
qiita.com

まあ、それはそれでさておき、「じゃあ、どうしたらいいの!?何をアウトプットすればあんたは満足するのさ!?」と思われる方も中にはおられるでしょう。

もちろん、その質問に対する回答についてはいろんなアプローチが考えられるのですが、今回は僕からひとつ、「アウトプット迷子」になっているプログラミング初心者さんに向けて、こんな提案をしてみたいと思います。

提案:シンプルなプログラミング問題を自力で解いて、そのコードをアウトプットしてみよう

僕がオススメするのは、シンプルなプログラミング問題を自力で解いて、そのコードをアウトプットする、というアプローチです。

このアプローチにはいろいろなメリットがあります。

  • アウトプットとして「自分で考えたコード」というオリジナルなコンテンツが得られます。
  • 問題を解く過程でいっぱい悩んで試行錯誤するはずなので、それが自分の実力アップにつながります(写経よりもずっと大変ですが、そのぶん写経よりもずっと勉強になります)。
  • 仕様が簡単なので、コードも軽量なものになり、他の人からコメントやフィードバックをもらいやすくなります(重厚長大なコードはアウトプットしてもなかなか読んでもらえません)。

ね?なかなか良さそうでしょう?

そこでいろんなプログラミング問題を集めてみました

とはいえ、今度はシンプルなプログラミング問題をどうやって集めてくるのかが問題になりますよね。

そんなあなたのために、プログラミング初心者でも比較的取り組みやすいプログラミング問題を集めてみました(全10問)。
以下で挙げているプログラミング問題は、これまで僕が実際に出題したり、解答したりしたことがあるものばかりです。

  • カレンダー作成問題
  • カラオケマシン問題
  • ビンゴカード作成問題
  • ボーナスドリンク問題
  • 電話帳作成問題
  • 国民の祝日.csv パースプログラム
  • 「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」問題
  • 行単位、列単位で合計値を求めるプログラム
  • ガラケー文字入力問題
  • 値札分割問題

難易度としては「プロを目指す人のためのRuby入門」(チェリー本)を一冊読めば十分解けるレベルです。
最後まで読まなくても、第6章(正規表現)までの知識でほとんど事足りると思います。

ですので、チェリー本を読み終わったら、もしくはある程度まで読み進めたら、ここに挙げたプログラミング問題にチャレンジして、その結果をアウトプットしてみましょう。

なお、問題が並んでいる順番に特に意味はありません。
自分が興味を持った問題や、難易度的に取り組めそうな問題からトライしてみてください。

あ、当然ですが、自力で解かなきゃ意味がないので、解答例を見てはいけませんよ!(解答例が載っている場合)

それでは、各問題の具体的な内容を以下で説明していきます。

カレンダー作成問題

「たのしいRuby」に載っている、オーソドックスなカレンダー作成問題です。
DateクラスのAPIさえわかれば、あとは基礎的なプログラミング知識だけでコードが書けると思います。

Date クラスを使って、今月の1日と月末の日付と曜日を求め、次のような形式でカレンダーを表示させてください

      April 2013
 Su Mo Tu We Th Fr Sa
     1  2  3  4  5  6
  7  8  9 10 11 12 13
 14 15 16 17 18 19 20
 21 22 23 24 25 26 27
 28 29 30

たのしいRuby 第6版 (Informatics&IDEA)

たのしいRuby 第6版 (Informatics&IDEA)

DateクラスのAPIについてはこちらを参考にしてみてください。

https://docs.ruby-lang.org/ja/latest/class/Date.html

カラオケマシン問題

その昔、僕がCodeIQに出題したプログラミング問題です。
たとえば、ドレミファソ(CDEFG)のキーを2つ上げて、レミファ#ソラ(DEF#GA)に変換するようなプログラムを作成します。

詳しい仕様は以下のエントリをご覧ください。

blog.jnito.com

ビンゴカード作成問題

1から75までの数字をランダムに配置して、ビンゴカードを作成するプログラミング問題です。
ただし、実際のビンゴカードのルールに沿って、各列は以下のような仕様で数字を出力する必要があります。

  • B:1~15のどれか
  • I:16~30のどれか
  • N:31~45のどれか
  • G:46~60のどれか
  • O:61~75のどれか

出力例は以下のとおりです。

 B |  I |  N |  G |  O
13 | 22 | 32 | 48 | 61
 3 | 23 | 43 | 53 | 63
 4 | 19 |    | 60 | 65
12 | 16 | 44 | 50 | 75
 2 | 28 | 33 | 56 | 68

これもやはり、以前CodeIQに出題した問題です。
詳しい仕様についてはこちらをご覧ください。

blog.jnito.com

ボーナスドリンク問題

「ある駄菓子屋で飲み物を買うと、空き瓶3本で新しい飲み物を1本プレゼントしてくれる。最初に100本購入した場合、トータルで何本飲めるか」という小学校3年生の算数の問題をベースにしたプログラミング問題です。

購入した本数 飲める本数
0 0
1 1
3 4
11 16
100 (プログラムで算出する)

詳しい仕様はこちらにあります。

https://github.com/JunichiIto/bonus-drink

電話帳作成問題

カタカナ文字列の配列を渡すと、ア段の音別にグループ分けした配列を返すプログラムを作成する問題です。

# INPUT
['キシモト', 'イトウ', 'ババ', 'カネダ', 'ワダ', 'ハマダ']

# OUTPUT 
[ ['ア', ['イトウ']], ['カ', ['カネダ', 'キシモト']], ['ハ', ['ハマダ', 'ババ']], ['ワ', ['ワダ']] ]

詳しい仕様はこちらにあります。

https://github.com/JunichiIto/name-index

国民の祝日.csv パースプログラム

その昔、「国民の祝日.csv」という扱いづらいCSVが話題になっていました。
具体的にはこんなCSVファイルです↓

平成28年(2016年),,平成29年(2017年),,平成30年(2018年),
名称,月日,名称,月日,名称,月日
元日,2016/1/1,元日,2017/1/1,元日,2018/1/1
成人の日,2016/1/11,成人の日,2017/1/9,成人の日,2018/1/8
建国記念の日,2016/2/11,建国記念の日,2017/2/11,建国記念の日,2018/2/11
春分の日,2016/3/20,春分の日,2017/3/20,春分の日,2018/3/21
昭和の日,2016/4/29,昭和の日,2017/4/29,昭和の日,2018/4/29
憲法記念日,2016/5/3,憲法記念日,2017/5/3,憲法記念日,2018/5/3
みどりの日,2016/5/4,みどりの日,2017/5/4,みどりの日,2018/5/4
こどもの日,2016/5/5,こどもの日,2017/5/5,こどもの日,2018/5/5
海の日,2016/7/18,海の日,2017/7/17,海の日,2018/7/16
山の日,2016/8/11,山の日,2017/8/11,山の日,2018/8/11
敬老の日,2016/9/19,敬老の日,2017/9/18,敬老の日,2018/9/17
秋分の日,2016/9/22,秋分の日,2017/9/23,秋分の日,2018/9/23
体育の日,2016/10/10,体育の日,2017/10/9,体育の日,2018/10/8
文化の日,2016/11/3,文化の日,2017/11/3,文化の日,2018/11/3
勤労感謝の日,2016/11/23,勤労感謝の日,2017/11/23,勤労感謝の日,2018/11/23
天皇誕生日,2016/12/23,天皇誕生日,2017/12/23,天皇誕生日,2018/12/23
,,,,,
月日は表示するアプリケーションによって形式が異なる場合があります。,,,,,

Excelで開くとこのように表示されます。

f:id:JunichiIto:20190503102150p:plain

これをいい感じにパースして、以下のようなデータ構造(Rubyのハッシュオブジェクト)に変換しよう、というプログラミング問題です。

{
  2016 => {
    # 実際のキーは文字列ではなくDateオブジェクト
    '2016/01/01' => '元日',
    '2016/01/11' => '成人の日',
    # ...
    '2016/11/23' => '勤労感謝の日',
    '2016/12/23' => '天皇誕生日',
  },
  2017 => {
    '2017/01/01' => '元日',
    '2017/01/09' => '成人の日',
    # ...
    '2017/11/23' => '勤労感謝の日',
    '2017/12/23' => '天皇誕生日',
  },
  2018 => {
    '2018/01/01' => '元日',
    '2018/01/08' => '成人の日',
    # ...
    '2018/11/23' => '勤労感謝の日',
    '2018/12/23' => '天皇誕生日',
  },
}

詳しい仕様についてはこちらをどうぞ。

qiita.com

「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」問題

テキストファイルの中から英熟語や英単語を抜き出してカウントする、という問題です。

# INPUT
Interior design and decorating resource Houzz is the overall best Android app of the year, (略)

# OUTPUT
単語数(熟語以外):331
英熟語?------------------------------------------------------------------
  2 Google I/O
  2 Google Play Awards
  1 And Google
  1 Best App
  1 Best Game
  1 Best of
  1 Best Standout Startup
  1 Best Use of Google Play Game Services
  1 Best Use of Material Design
  (略)
英単語------------------------------------------------------------------
 22 the
 11 and
 11 of
  8 a
  6 apps
  5 app
  5 best
  5 for
  5 Google
  5 to
  4 that
  4 this
  (略)

詳しい仕様についてはこちらをご覧ください。

qiita.com

行単位、列単位で合計値を求めるプログラム

Excelのように、格子状に並んだ数値に対して、行方向の合計値と列方向の合計値をそれぞれ求める問題です。

たとえばこういうインプットであれば、

- col1 col2 col3 col4
row1 9 85 92 20
row2 68 25 80 55
row3 43 96 71 73
row4 43 19 20 87
row5 95 66 73 62

こういう結果になります。

- col1 col2 col3 col4 sum
row1 9 85 92 20 206
row2 68 25 80 55 228
row3 43 96 71 73 283
row4 43 19 20 87 169
row5 95 66 73 62 296
sum 258 291 336 297 1182

実際にはそれぞれ、以下のような配列オブジェクトとして扱います。

input = [
    [9, 85, 92, 20],
    [68, 25, 80, 55],
    [43, 96, 71, 73],
    [43, 19, 20, 87],
    [95, 66, 73, 62]
]
expected = [
    [9, 85, 92, 20, 206],
    [68, 25, 80, 55, 228],
    [43, 96, 71, 73, 283],
    [43, 19, 20, 87, 169],
    [95, 66, 73, 62, 296],
    [258, 291, 336, 297, 1182]
]

詳しい仕様についてはこちらをご覧ください。

qiita.com

ガラケー文字入力問題

ガラケーの文字入力(アルファベット入力)をシミュレートするプログラミング問題です。

P111 Chinese Mobile Phone

英語のガラケーでは「2」キーを2回押すと「b」になり、「3」キーを3回押すと「f」になります。
ただし、この問題では特別ルールとして「0」で文字を確定させます。

たとえば、このプログラムに対して"440330555055506660"を入力すると、"hello"が返ってきます。

詳しい仕様についてはこちらはこちらをご覧ください。

Keitai Message | Aizu Online Judge

値札分割問題

「値段らしき文字列」を「数字部分」と「単位部分」に分割する、split_priceメソッドを作ってください、というプログラミング問題です。

split_price '110.0万円'     #=> ['110.0', '万円']
split_price '2015円'        #=> ['2015', '円']
split_price '1,123,456円'   #=> ['1,123,456', '円']
split_price '110 - 120万円' #=> ['110 - 120', '万円']
split_price '2015円'    #=> ['2015', '円']
split_price '価格未定'      #=> ['価格未定', '']
split_price nil             #=> ['', '']

詳しい仕様についてはこちらをどうぞ。

qiita.com

参考情報:熟練者であれば回答に必要な時間は30分から1時間ぐらい?

僕だったらどの問題も30分から1時間ぐらいかければ、「とりあえず要件通りに動くコード(とテストコード)」は書けると思います。
そして、それが終わったら時間の許す限りコードをリファクタリングする、というアプローチを取ります。
(リファクタリングをするので、テストコードは必須です!)

初心者さんはもっとたくさん時間がかかると思いますが、ひとつの目安として参考にしてみてください。

2019.5.20追記:できればロジック本体と画面出力はきちんと分離しよう

これらの問題にチャレンジした方のコードを見ていると、putsやprintを多用して、出力結果を組み立てている方が多いようです。
最初の実装はそれでもよいのですが、最終的にはロジック本体と画面出力を分離して、テストコードまで追加するのが理想的です。

詳しくは以下のQiita記事をご覧ください。

qiita.com

まとめ

というわけで、このエントリではプログラミング初心者でも取り組みやすい、シンプルなプログラミング問題を紹介してみました。

どうですか?自力で解けそうな問題はありましたか?

独学で取り組むのもよいですが、できれば仲間を集めて同じ問題に取り組み、最後にお互いにコードレビューしあったりすると、さらに勉強の効果がアップすると思います。

そして、最後に「僕が考えたコードはこれです!」という内容をアウトプットしてみてください。
きっと本や他サイトの内容を写経するよりも、ずっと良いアウトプットが得られると思います。
みなさんの頑張りに期待しています!

宣伝:Rubyの学習にはこれ!「プロを目指す人のためのRuby入門」

今回紹介したプログラミング問題は、基本的なRubyの知識があれば解けるものばかりです。
いずれもRuby on Railsの知識は必要ありません。

僕が執筆した「プロを目指す人のためのRuby入門」を熟読すれば、「解答に必要なRuby関連の基礎知識」はほとんどキャッチアップ可能です。

プログラミングに関する勉強は、あちこちに転がっているネットの情報をつまみ食いして勉強するよりも、本を使って一度体系的に勉強した方が、実は効率的だったりします。
本書をまだ読んだことがないという方は、ぜひ一度お近くの書店で手に取ってみてください😃