B - Judge Status Summary(ABC173復習)

7月5日に開催されたAtCoder Beginner Contest 173

B問題の復習。

B - Judge Status Summary

問題文
高橋君は、プログラミングコンテスト AXC002 に参加しており、問題 A にコードを提出しました。
この問題には N 個のテストケースがあります。各テストケース i ( 1 ≤ i ≤ N ) について、ジャッジ結果を表す文字列 Si が与えられるので、ジャッジ結果が AC, WA, TLE, RE であったものの個数をそれぞれ求めてください。

入力例
6
AC
TLE
AC
AC
WA
TLE

出力例
AC x 3
WA x 1
TLE x 2
RE x 0

B - Judge Status Summary

提出したコード

s = readlines.map(&:chomp)
puts "AC x #{s.count("AC")}"
puts "WA x #{s.count("WA")}"
puts "TLE x #{s.count("TLE")}"
puts "RE x #{s.count("RE")}"

結果:AC(正解) 実行時間:110 ms

readlinesは、各行を配列として返すメソッド。 sはこうなっている。

p s
#=> ["6", "AC", "TLE", "AC", "AC", "WA", "TLE"]

s の中の特定の文字列の数をcountメソッドで数えて、そのまま出力。

うーん、DRYじゃないのが気になる。

もっといいコード

他の人のコードを見ていて、tallyというメソッドを初めて知った。

p ["a", "b", "c", "a", "c"].tally
#=> {"a"=>2, "b"=>1, "c"=>2}

英単語の tally は「集計」という意味で、このように要素の数をハッシュで返してくれる。

Enumerable#tally (Ruby 2.7.0 リファレンスマニュアル)

これを使ってみたい!

gets
s = readlines.map(&:chomp).tally
["AC", "WA", "TLE", "RE"].each do |w|
  puts "#{w} x #{s[w] || 0}"
end

1行目のgetsは、1行目に渡される入力値の行数を読み込むためのもの(s に入ると邪魔なので)。今回のコードでは使わないので特に代入などはしていない。

"AC", "WA", "TLE", "RE" の4つが必ず登場するなら puts "#{w}"でいいが、入力例のように、"RE"は1回も出てこないというような場合、表示されない。

一つもない場合に0を表示させるために、puts "#{w} x #{s[w] || 0}"とした。

||は or(または)を意味する演算子。これは、まず左辺を評価して左辺が真だった場合、左辺の評価結果を返す。左辺が偽だった場合は右辺を評価し、右辺の評価結果を返す。

つまり、s[w] || 0は、s[w]が真だった場合はその値を返し、nil(s に一度も出てこない文字列)の場合には0を返すことになる。

演算子式 (Ruby 2.7.0 リファレンスマニュアル)

感想

新たな発見があってよかった。||も理解はしていたが実際あまり使ったことがなかったので、いい勉強になった。