ハッシュの使い方

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

#前提
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

#解き方

```ruby
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で出力してあげれば、
期待通りの答えになります。

以上です。