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
提出したコード
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
を返すことになる。
感想
新たな発見があってよかった。||
も理解はしていたが実際あまり使ったことがなかったので、いい勉強になった。