0
0

More than 3 years have passed since last update.

ハッシュの使い方

Posted at

これまで配列を多用していたのですが、
ある問題を解いていた時に配列だけでは解決できず、
ハッシュで解決できました。
その学びについてのメモ。

前提

Aさん、 Bさん、 Cさんの書籍購入費ランキングを作成する。
Aさん、 Bさん、 Cさんという名前の 3人のエンジニアがおり、
それぞれ 1000円, 3000円, 2000円 の書籍購入費を消費。
この場合、 Bさんが 1位となり、 Cさんが 2位、そして Aさんが 3位となる。

それぞれのエンジニアの名前と、書籍の購入情報が与えられるので、
この情報から書籍購入費ランキングを作成する。

入力

3    -> エンジニアの人数( number_of_engineers )
A B C  -> エンジニアの名前( name_of_engineers )
4    -> エンジニアたちが購入した本の数( number_of_books )
A 1000 -> 本を購入したエンジニアの名前とその本の金額( name, price )
B 1000
B 2000
C 2000

出力

B
C
A

解き方

number_of_engineers = gets.to_i 
name_of_engineers = gets.to_s.split(" ") 
number_of_books = gets.to_i 
name_n_price = {}
name_of_engineers.each{|name| name_n_price[name] = 0}  #解説1
number_of_books.times do
  name, price = gets.to_s.split(" ")
  name_n_price.each_key{ |i| name_n_price[i] += price.to_i if i == name}  #解説2
end
puts name_n_price.sort_by{ |name, price| -price}.to_h.keys  #解説3

解説

解説1

事前に"name_n_price"で空のハッシュを生成しています。
name_of_engineersは現時点で以下のようになっています。

name_of_engineers = ["A", "B", "C"]

この配列の要素(A, B, C)をeachメソッドで取得し、name_n_priceの中のキーとして加えていきます。
また、この時、name_n_price[name] = 0としているので、各キーには 0というバリューが入ります。
この後、"A 1000"などが入力されていくため、初期値の設定として、上記のようにしています。
上記操作によって、"name_n_price"は以下のようになります。

name_n_price = {"A"=> 0, "B"=> 0, "C"=> 0}

解説2

number_of_books.times do ~ end で "A 1000"など計4回の入力を行わせます。
(今回はnumber_of_books = 4)
name, price = gets.to_s.split(" ")にて以下のような配列を生成させます。

name, price = ["A", "1000"]

続いて、name_n_priceのハッシュ内の各キーに対して、値を追加していきます。
そのため、name_n_price内の各要素をeachメソッドで取得していくのですが、
今回はキーのみの取得を行っていきます。
理由はハッシュのキーに値を追加していく事を理解できていれば、
おさらいしておきます。

irb(main):011:0> h = {} 
=> {}
irb(main):012:0> h[:name] = "suzuki"
=> "suzuki"
irb(main):013:0> p h
{:name=>"suzuki"}
=> {:name=>"suzuki"}

要はキー(今回で言う"name")があれば、値(今回で言う"suzuki")を指定して追加が可能です。

そのため、" name_n_price.each_key{} "とします。
他にはバリューだけ取り出すeach_valueもあります。

続いて、name_n_price = {"A"=> 0, "B"=> 0, "C"=> 0}に対して、
Aさんに該当した場合に値を追加していきたいので、if分で条件分岐を行います。
以下の通りです。

if i == name

ここでの " i "には A, B, Cが入ります。
( each_key でキーを取得しており { |i| ~ }としているため)

最後に入力された金額(price)を加えていきます。

name_n_price[i] += price.to_i

上記を分解して書くと、

name_n_price[i] = name_n_price[i] + price.to_i

代入値で書くと

name_n_price[A] = 0 + 1000

なので、

name_n_price = {"A"=> 0, "B"=> 0, "C"=> 0}

name_n_price = {"A"=> 1000, "B"=> 0, "C"=> 0}

になります。

これをあと三回繰り返すと結果的に

name_n_price = {"A"=> 1000, "B"=> 3000, "C"=> 2000}

になります。

解説3

最後にname_n_priceに対して、金額が大きい人からそのキー(名前)を順番に出力します。

ハッシュ内の金額を大きい順(降順)にしたいので、sort_byを使用します。
sortもありますが、こちらはキーでの並び替えであるため、今回は使えません。

ちなみに、使うとこんな感じになります。

irb(main):017:0> h = {"z" => 1, "f" => 3, "a" => 5}
=> {"z"=>1, "f"=>3, "a"=>5}
irb(main):018:0> h.sort
=> [["a", 5], ["f", 3], ["z", 1]]

キーがアルファベット順で並び替えられています。

以下のようにする事で、値を降順にできます。

name_n_price.sort_by{ |name, price| -price}
irb(main):019:0> name_n_price = {"A"=> 1000, "B"=> 3000, "C"=> 2000}
=> {"A"=>1000, "B"=>3000, "C"=>2000}
irb(main):020:0> name_n_price.sort_by{ |name, price| -price}
=> [["B", 3000], ["C", 2000], ["A", 1000]]

これで並び替えができましたが、ハッシュから配列に要素が格納されています。
これは、sort_byやsortを実行すると、なってしまいます。
なぜかは不明です。

今回の条件ではキーだけを取得したいので、
配列をハッシュに戻して、キーを取得します。

配列をハッシュに変換するには、to_hメソッドを使用します。

name_n_price.sort_by{ |name, price| -price}.to_h
=> {"B"=>3000, "C"=>2000, "A"=>1000}

また、キーだけ欲しいので、keysメソッドを使用します。

name_n_price.sort_by{ |name, price| -price}.to_h.keys
=> ["B", "C", "A"]

putsメソッドでは改行されるので、上記をputsで出力してあげれば、
期待通りの答えになります。

以上です。

0
0
4

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
0
0