Hatena::Grouprubyist

うんたらかんたらRuby RSSフィード

2008-12-21csvのパース

csvのパース

| csvのパース - うんたらかんたらRuby を含むブックマーク はてなブックマーク - csvのパース - うんたらかんたらRuby

普段雑務でcsvの各値を集計したり計算したりするっていうのを

定常的に行っているのでrubyでスクリプト化してみた。


書いてみた

こんな感じでcsvファイルを順に読込み

カンマでsplitして、ダブルクォーテションをsubで置換して、と。

Dir.glob("*.csv") do |file_name|
(一部略)
  file = open(file_name, "r")
  file.gets
  file.each do |f|
    vals = f.split(',')
    f1 += vals[1].sub(/^\"/,"").sub(/\"$/,"").to_f
(一部略)


csvパーサーが付いていた

どうも、sub置換とか面倒なのでパーサーって無いのかと調べたら

標準であった。

簡単やん。

require 'csv'
CSV.open('in.csv', 'r') do |row|
  p row
end

fastercsvを使ってみた

でも遅いらしいのでfastercsvをインストール。

Rubyの標準添付CSVパーサーが遅い - 技術メモ帳


こっちも簡単。

require 'rubygems'
require 'fastercsv'
FasterCSV.foreach('in.csv') do |row|
  p row
end
トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081221

2008-12-20移行20080320:またもやgolf

またもやgolf

| 02:33 | またもやgolf - うんたらかんたらRuby を含むブックマーク はてなブックマーク - またもやgolf - うんたらかんたらRuby

ruby関係はこっちに纏めるために移行。


こんなのがあった。

Rubyist Magazine - るびまゴルフ 【第 2 回】


27byteがパーに設定されているので

とりあえずパー目指してラウンドしてみた。


原型

-2000.step(-10000,-10) do |v|
  puts v
end

さっそくチャレンジ。

200.upto(1000){|v|puts -v*10}

30byte まだトリプルボギー。



最終結果

他の人の回答を覗いてみると

[1000]を[1e3]と書いている。なるほど。

あと、数値だから[p]でよいのだと気づいた。

200.upto(1e3){|v|p -v*10}

26byte やった!バーディー!

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081220

2008-12-07移行20080316:golf checkers+pattern

golf checkers+pattern

| golf checkers+pattern - うんたらかんたらRuby を含むブックマーク はてなブックマーク - golf checkers+pattern - うんたらかんたらRuby

ruby関係はこっちに纏めるために移行。


懲りずにgolf。

anarchy golf - checkers pattern


golf ver. 最終的にこうなった

a,b=gets.split.map{|x|x.to_i}
a.times{|x|s=[];t=(x+1)%2
b.times{|y|s<<t;t=-t+1}
puts s*(" ")}

大分すっきりした感あり。

他の人はeval使ってるなぁ。


golfは短い書き方を覚えれていい面もある。

今日は、配列の初期化が [] だけでできることと

array.join が * だけでできることを学んだ。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081207

2008-12-06移行20080315:golf seg

golf seg

| golf seg - うんたらかんたらRuby を含むブックマーク はてなブックマーク - golf seg - うんたらかんたらRuby

ruby関係はこっちに纏めるために移行。


golfに興味が湧いてきた。w

anarchy golf - segs


golf ver. 最終的にこうなった

a=gets;s=a.size;1.upto(s){|i|i.times{|y|puts a[(s-i),y+1]}}

改行付き ver.

a=gets
s=a.size
1.upto(s){|i|
  i.times{|y|
    puts a[(s-i),y+1]
  }
}

ようやく一人抜かした。w

おもしろいけど、自己満足だなぁ。

きれいで直感的に分かりやすいコードを目指そう。

f:id:rochefort:20080315050133p:image

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081206

2008-12-03Nokogiriを使ってみた

Nokogiriを使ってみた

| Nokogiriを使ってみた - うんたらかんたらRuby を含むブックマーク はてなブックマーク - Nokogiriを使ってみた - うんたらかんたらRuby

fizzbuzzをやってみた - うんたらかんたらRuby - Rubyist

anarchy golf - FizzBuzz

golfでは、67位なんだけど早さでは何位なんだろうかと思って

scrapeしてsortしてみようと思い立った。



ここら辺(Ruby Scraping - FrontPage)をみながら

xpathとかcssセレクタとかを簡単に扱えるらしい。」ということで

Nokogiri(tenderlove's nokogiri at master — GitHub)をインストールしてみることに。


インストール

gem install nokogiri

で簡単に入れれるらしい。

Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.

でもエラー。。

gemを更新して再度やったらうまくいった。

gem update --system


早速使ってみる

xpathで簡単にデータが取得できるのはわかったけど、

このhtmlanarchy golf - FizzBuzz)には

idとかclassとかが適切に設定されていないので

Rubyの結果だけを抜き出せるようなxpathが書けない。


htmlの構造は↓みたいな感じになってる。

 html

 body

 a Ruby(言語名)....

 table Rubyの結果

 a Perl(言語名)....

 table Perlの結果

  ・

  ・

  ・

悩んだ結果、「言語名のaタグ」の後に「結果のtableタグ」が必ずくるので

それぞれ別々の配列に取得して、使う時に同じindexを使えば

欲しい言語の結果が取り出せそう。


書いてみた

require 'rubygems'
require 'nokogiri'
require 'open-uri'
  
abort('no argument err.') if ARGV.size == 0

doc = Nokogiri::HTML(open('http://golf.shinh.org/p.rb?FizzBuzz#Ruby'))

#言語名を配列にセット
prog_names = []
doc.xpath('/html/body/h3/a[@href]').each do |nsa|
  href = ""
  href = nsa.get_attribute("href")
  if href =~ /\/l\.rb\?.*/
    prog_names << nsa.inner_text
  end
end

#tableタグを配列にセット
#tables最後のtable要素は「Language Ranking」が含まれる。(言語名より1つ多い)
tables = []
tables = doc.xpath('/html/body/table')

rank_info = Hash.new
prog_names.each_with_index do |prog, i|
  if ARGV[0].upcase == prog.upcase
    p prog
    tables[i].xpath('tr').each do |tr|
      user = tr.xpath('td[2]').inner_text
      time = tr.xpath('td[4]').inner_text
      if user != "" && time != ""
        rank_info[user] = time
      end
    end
  end
end

puts "Rank User Time"
puts "------------------------------"
rank_info.sort_by {|key, val| val}.each_with_index{|x, n| puts "#{n + 1} #{x[0]} #{x[1]}"}

引数で指定した言語の結果を早さ順に並べ替えます。


結果

$ ruby noko.rb ruby
"Ruby"
Rank User Time
------------------------------
1 leonid (alnum) 0.0003
2 Duane Bailey 0.0071
3 Matthew 0.0118
4 crazyjimbo 0.0171
5 khtokage 0.0197
6 yuya 0.0296
7 rawwell 0.0302
8 flagitious(alnum) 0.0344
9 rickrickrick 0.0355
10 shrapnel 0.0373
11 rochefort 0.0373
12 Steve Cooper 0.0432
13 mokos 0.0487
14 lw 0.0491
15 smly 0.0492


以下略

なんとか、11位(同順で10位。ここは考慮できてない)。


疑問点

今回は、sorthashを利用したけど、構造体の配列みたいなので本当はやりたい。

でもよくわかんない(2次元配列とかのソートが)。

user名でソートとかを簡単にするには、多次元配列のソートを書かないといけないのかな。

簡単にできる方法はないのかな。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081203

2008-12-02NabeAtzzを今更ながらやってみた

NabeAtzzを今更ながらやってみた

| NabeAtzzを今更ながらやってみた - うんたらかんたらRuby を含むブックマーク はてなブックマーク - NabeAtzzを今更ながらやってみた - うんたらかんたらRuby

fizzbuzzをやってみた - うんたらかんたらRuby - Rubyist

で思い出したので、↓をやってみた。

そろそろ FizzBuzz に飽きた - にぽたん研究所


やってみた

#!/usr/bin/ruby -Ku
def nabeatzz(num)
  if num % 3 == 0 || /3/ =~ num.to_s
    num_to_japanese(num)
  else
    num
  end
end


def num_to_japanese(num)
  rtn = ""
  #変換文字列
  figures = ["","いち","","さん","よん","","ろく","なな","はち", "きゅう"]
  units   = ["まん","せん","ひゃく","じゅう",""] 

  #units配列のどの位置から使用するかを桁数から算出
  unit_start_index = units.size - num.to_s.length
  
  #数値を日本語に変換
  num.to_s.scan(/./).each_with_index do |n, i|
    # "1"でない または 最後の1桁でない場合のみ変換
    #if n != "1" バグ修正コメント参照
    if n != "1" || num.to_s.length == i + 1
      rtn << figures[n.to_i]
    end
    #単位を追記
    if n != "0"
      rtn << units[unit_start_index + i]
    end
  end
  rtn
end

(1..100).each {|i| puts nabeatzz(i)}
#(100..1000).each {|i| puts nabeatzz(i)}
#(1000..10000).each {|i| puts nabeatzz(i)}

結果

1
2
さん
4
5
ろく
7
8
きゅう
10
11
じゅうに
じゅうさん
14
じゅうご
16
17
じゅうはち
19
20
にじゅういち
22
にじゅうさん
にじゅうよん
25
26
にじゅうなな
28
29
さんじゅう
さんじゅういち
さんじゅうに
さんじゅうさん
さんじゅうよん
さんじゅうご
さんじゅうろく
さんじゅうなな
さんじゅうはち
さんじゅうきゅう
40

以下略

figures/units配列に空白値をもたせることでif分岐が減って、ちょっとすっきりしました。

300代、3000代は「びゃく」「ぜん」に変換しないといけないけど、まぁええか。

to_s.scanした後to_iするのが、なんかいや。

rochefortrochefort2008/12/01 23:33あ、今日流行語大賞発表だったんですね。受賞逃したのか。
でも、なんかタイムリー。

rochefortrochefort2008/12/02 22:11バグっとるやんけ。
ということで2点修正。

1点目:最後の一桁が1の場合、変換されていないバグ
    31→さんじゅう になっていたのを修正。
2点目:2桁目以上が0の場合、不要な単位(ひゃく、じゅう)が付与されていたバグ
    102→ひゃくにじゅうに になっていたのを修正。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20081202

2008-12-01移行20080314:fizzbuzzをやってみた

fizzbuzzをやってみた

| fizzbuzzをやってみた - うんたらかんたらRuby を含むブックマーク はてなブックマーク - fizzbuzzをやってみた - うんたらかんたらRuby

ruby関係はこっちに纏めるために移行。


ちょくちょく話題に上るfizzbuzz

頭でロジックは立つが実際書いたことはないので

書いてみた。


何も考えずにやってみた

(1..100).each {|x| 
        if x % 15 == 0
                puts "FizzBuzz"
        elsif x % 3 == 0
                puts "Fizz"
        elsif x % 5 == 0
                puts "Buzz"
        else
                puts x
        end
}

剰余なしでやってみた

↓をちらっと見て、剰余[%]を使用しないで解いたもの。

頭の体操になるか? - octech

def joyo(x, y)
        return x - ((x / y).to_i * y)
end

(1..100).each {|x| 
        if joyo(x, 15)  == 0
                puts "FizzBuzz"
        elsif joyo(x, 3) == 0
                puts "Fizz"
        elsif joyo(x, 5) == 0
                puts "Buzz"
        else
                puts x
        end
}

剰余をお手製で作っただけ。。


golfしてみた

↓にランキングが紹介されていたのでsubmitしてみた。

anarchy golf - FizzBuzz

(1..100).each{|x|s="";s="Fizz" if x%3==0;s+="Buzz" if x%5==0;s=x if s=="";puts s}

改行削除。空白を可能な限り削除。

これで61位かぁ。上には上がいるなぁ。

でも早さなら結構いい線いってる?

f:id:rochefort:20080315002538p:image


三項演算子版

いつの間にか、三項演算子大好きになってしまってた。

(1..100).each{|x|puts x%15==0?"FizzBuzz":x%3==0?"Fizz":x%5==0?"Buzz":x}

rochefortrochefort2008/12/01 01:55http://golf.shinh.org/p.rb?FizzBuzz#Ruby
今見たら、67位でした。

今更だが、3項演算子を使えばいい感じになりそうかなぁ。(でも3項演算子は嫌い)