13日金曜日再び、パイプ処理的な

1902年から2037年までの各年に、13日の金曜日が何日あるかを数え上げるスクリプトを書き換えてみた。集計のためのハッシュを用意する代わりに、Array#productを使って生成した配列をごにょごにょっといじる間に答えが出るようにしてみた。

years = (1902..2037).to_a
months = (1..12).to_a

def is_friday?(y,m,d)
  Time.mktime(y,m,d).to_a[6] == 5 # FRIDAY
end

years.each{|year|
  print year,":", years.product(months).map!{|y,m|
    is_friday?(y,m,13) ? [y,"jason"] : [y,m]
  }.select{|y,m| y == year && m == "jason"}.size,"\n"
}

やってることは単純だけど、なんかめちゃくちゃ読みづらいコードになってしまった。しかも、驚くことに実行速度が目に見えて遅くなった。そんなにオーバーヘッドがあるように思えないけど、文字列が出てくるのが目で追えるほど遅い。

やっぱり普通(?)に、

years.each{|y|
  months.each{|m|
    if is_friday?(y,m,13)
      jason[y] = jason[y] + 1
    end
  }
}

と書くほうがいい。もっといいのは、コマンドラインから、

for i in `seq 1970 2020`; do for j in `seq 1 12`; do date -d "$i-$j-13" +"%a %Y %m %d"; done; done|grep ^Fri|cut -d" " -f2|uniq -c

と書くことだったりして。Unixのパイプ処理って、Rubyでメソッドやブロックを並べるのと似てる気がする。長いパイプ処理を書くときって、結果を少しずつ確認しながら、その中間生成物をさらに加工するというようなことはやっても、中間生成物を変数に入れようとかファイルに落とそうということはあまりしない。もしかすると、そういう発想があるから、Rubyでもテンポラリにデータを保持するのとか、処理ブロックが2系統に分かれるのを気持ち悪く感じるのかも。