Ruby初心者向けプログラミング問題10選を解いてみた(上)の続きです
引き続き自分の回答を貼っていきますが、2問解けてないです(へなちょこ)
素晴らしき元サイト様
アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)
国民の祝日.csv パースプログラム (回答無し)
問題文
問題文(折りたたみ)
コード
csvの扱い方が全くわからなかったので解けなかったです…
代わりと言ってはなんですが本家の模範解答のURLを貼っておきます
【短命に終わった】国民の祝日.csvをパースして変換するRubyプログラムとコード解説動画
要点解説
解説動画です
【短命に終わった】国民の祝日.csvをパースして変換するRubyプログラムとコード解説
「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」問題
問題文
問題文(折りたたみ)
入力に使うテキストファイルはこんな感じです。
Interior design and decorating resource Houzz is the overall best Android app of the year, according to Google, which this evening announced the results of the first-ever Google Play Awards at its developer conference, Google I/O.
(略)
出力結果はこんな感じになります。
単語数(熟語以外):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
(略)
コード
*かなりゴチャゴチャしてます
*熟語の判定がガバガバなので本家と出力結果が違います
file_pass = # 任意のパス
sentence = File.read(file_pass)
words = []
idioms = []
# 英熟語を抜き出す
while (idiom = sentence.slice!(/[A-Z]\w*(?:[\/\s-]+[A-Z]\w*)+/))
idioms << idiom
end
idioms_hash = idioms.tally
# 記号系を消す
while (s = sentence.slice!("’s"))
words << s
end
sentence.gsub!(/[,.“”?!;:ー"–]/, " ")
# 単語を抜き出す
words << sentence.split
words.flatten!
words_hash = Hash.new(0)
words.each { |word| words_hash[word.downcase] += 1}
# ソート
idioms_hash = idioms_hash.sort_by { |idiom, freq| [-freq, idiom] }.to_h
words_hash = words_hash.sort_by { |word, freq| [-freq, word] }.to_h
# 出力
puts "単語数 : #{words.count + idioms.count}"
puts "英熟語?-----------------------------------------------------------------"
idioms_hash.each { |word, num| puts "#{num} #{word}" }
puts "英単語------------------------------------------------------------------"
words_hash.each { |word, num| puts "#{num} #{word}" }
要点解説
while (idiom = sentence.slice!(/[A-Z][\w]*(?:[\/\s-]+[A-Z][\w]*)+/))
idioms << idiom
end
(idiom = sentence.slice!(/[A-Z][\w]*(?:[\/\s-]+[A-Z][\w]*)+/))
は条件式の中で警告を出さずに変数代入を行う書き方です(カッコを外すと警告が出ます)
idioms_hash = idioms_hash.sort_by { |idiom, freq| [-freq, idiom] }.to_h
words_hash = words_hash.sort_by { |word, freq| [-freq, word] }.to_h
sort_by
メソッドでは、レシーバの各要素を<=>
で比較します
配列を<=>
で比較すると、各要素を順番に比較し0でない値が出た時その値を返します
なので、[-freq, idiom]
と書くとまずfreq
の値でソートし、もし同じ値だったらidiomをアルファベット順に並べる、ということができます
sortの結果は配列になっているのでto_h
でハッシュに戻します(執筆中に気づきましたがここは配列のままでも動作するみたいです)
行単位、列単位で合計値を求めるプログラム
問題文
問題文(折りたたみ)
たとえばこういうインプットであれば、
- | 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 |
ただし、出題元のブログでは以下のような仕様になっていました。
- ランダムに数字を出力する
- 計算結果は以下のようなフォーマットで出力する
9| 75| 83| 74| 241
0| 27| 32| 48| 107
51| 66| 76| 3| 196
2| 37| 69| 85| 193
55| 40| 25| 88| 208
117| 245| 285| 298| 945
コード
class SumMatrix
class << self
def sum
matrix = generete_matrix
matrix = sum_matrix(matrix)
format_matrix(matrix)
end
def generete_matrix
Array.new(5) { Array.new(4) { rand(100) } }
end
def sum_matrix(matrix)
2.times do
matrix.each { |ary| ary << ary.sum }
matrix = matrix.transpose
end
matrix
end
def format_matrix(matrix)
matrix.each { |elem| elem.map! { |x| x.to_s.rjust(4) } }
matrix.map! { |elem| elem.join("|") }
matrix.join("\n")
end
end
end
要点解説
class << self
endまでで定義したメソッドがクラスメソッドとして定義されます
ネストは増えるけど便利
Array.new(5) { Array.new(4) { rand(100) } }
Array.new
は第1引数に要素数、第2引数に中身を指定してデフォルト値(?)を作れます
しかし、出来上がった配列の中身はすべて同じオブジェクトを参照しているのでうまく動きません
なので別々のオブジェクトを与えるためブロックを使っています
また、常に重複した値が出る可能性があるようにしています
このコードを教えてくださったコメント欄の@scivolaさんに感謝
matrix.each { |elem| elem.map! { |x| x.to_s.rjust(4) } }
例えば[1,2], [3, 4]
を[[" 1", " 2"], [" 3", " 4"]]
にします
ここはもうちょっといい書き方があった気がします
ガラケー文字入力問題
問題文
問題文(折りたたみ)
たとえば、このプログラムに対して"440330555055506660"を入力すると、"hello"が返ってきます。
コード
*keitai_messageの引数はStringとして取っていますが、これはIntegerとするとメソッド呼び出しのとき8進法の数と解釈されてエラーを起こすことがるからです
*入力を10進法のリテラルにするのも違うかな、と考えこうしました
CHARSES = {
"1" => %w(. , ! ? \ ),
"2" => %w(a b c),
"3" => %w(d e f),
"4" => %w(g h i),
"5" => %w(j k l),
"6" => %w(m n o),
"7" => %w(p q r s),
"8" => %w(t u v),
"9" => %w(w x y z)
}.freeze
def keitai_message(message)
nums = message.scan(/([123456789]+)0/).flatten
return if nums.empty?
nums.map! do |num|
chars = CHARSES[num.chr]
index = (num.size % chars.size) - 1
chars[index]
end
nums.join
end
要点解説
nums = message.scan(/([123456789]+)0/).flatten
scanの引数の正規表現にカッコが含まれる場合、カッコの内側にマッチした文字列が配列になって返ります
つまり、"01022"は[["1"], ["22"]]になるわけですね
値札分割問題 (回答無し)
問題文
問題文(折りたたみ)
コード
全然わかりませんでした…!
なので本家の模範解答のURLを貼っておきます
【Rubyプログラミング問題】値札分割メソッド(split_price)を作成してください:解答編
おわり
以上、「Ruby初心者向けプログラミング問題10選を解いてみた」でした
ここまで読んでいただき本当にありがとうございました!