Just do IT

思うは招く

Ruby基礎問題100本ノック#2 文字列から単語数をカウントしてハッシュで表現する

お題:文字列に出現する単語数を数えてみよう

問題:文字列no pain no gainに出てくる単語の個数を数えて、ハッシュで表現しよう

問題については以下の記事を参考にした。 qiita.com

回答

string = 'no pain no gain'
hash = Hash.new(0)
string.split(' ').each { |word| hash[word] += 1}

合計すると2時間くらいかかってしまった…。まだまだレベルが足りない証拠だ。

解説

Hash.newをして空ハッシュを作る。 ただし、ここで

hash = {}

と空ハッシュを作って実行すると、以下のエラーが返ってきてしまう。

undefined method `+' for nil:NilClass

ハッシュに対して存在しないキーを指定するとnilが返り、「このメソッドは定義されてないよー」と教えてくれている。

 hash = {}
 hash[:foo]
=> nil
hash = Hash.new('hello')
hash[:foo]
=> "hello"

なので、Hash.new(0)と最初に0を入れる。するとこうなる。

hash = Hash.new(0)
p hash[:a] = 10
p hash[:b]
p hash[:c]
=>
10
0
0
# :a以外は初期値が0になっていることがわかる

あとはsplitメソッドを使って文字列を単語で区切って配列に入れる。 eachメソッドにブロックを渡し、ブロック内ではそれぞれの単語が出てきたら、単語をキーにして値に数値の1をプラスしていく。

つまり、最初のnoが出てきたときにはその値が1になり、2回目のnoが出てきたとき、すでに最初の1があるので、それに1を足して2になる。

反省

[Ruby][解答募集]文字列に出現する単語の個数を数えてみよう - Qiita

本家の記事に投稿されているコードを見ると、皆さんdefを使ってメソッド名をつけて引数も設定している。これがプロの作法なんだと学んだ。

Ruby入門本として有名な「チェリー本」の著者である伊藤さんもブログで次のように言っている。

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

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

つまり今回書いたコードは次のように書き直せる。

string = 'no pain no gain'
def count_string(string)
  hash = Hash.new(0)
  string.split(' ').each { |word| hash[word] += 1}
  puts hash
end
count_string(string)

ただ、これだとputs hashがメソッドの中にあるので、こっちのほうがいいのかも?

string = 'no pain no gain'
@hash = Hash.new(0)
def count_string(string)
  string.split(' ').each { |word| @hash[word] += 1}
end
count_string(string)
puts @hash