簡易版 Ruby チュートリアル
はじめに
本資料では Ruby のスクリプト言語としての基本的な使い方を紹介する.
本資料は以下の Web を元にしている.
また, 数値データの利用には numo-narray を用いる. numo-narray のメソッドについては以下を参照されたい.
Ruby を動かしてみる
RubyはPerlやシェルスクリプトと同じようなスクリプト言語です. スクリプトを記述したファイルをつくりRubyを呼ぶと, 中身が実行されます.
エディタ vi で中身が
print("Hello, World\n")
と書かれたファイルをつくり, test1.rb という名前で保存します. そして
$ ruby test1.rb
とコマンドを実行すると
Hello, World
と表示されます. スクリプトは「""でくくられた部分(=文字列)を表示せよ」というものです. 「\n」は改行を表します.
先頭に "#! /usr/bin/env ruby" と書いておき, chmod +x で実行可能にしておけば, $ ./〜.rb ですみます. 以下のような test2.rb を作成し,
#! /usr/bin/env ruby print("こんにちわ, 世界\n") # ここはコメント
これを実行してみましょう.
$ chmod +x test2.rb $ ./test2.rb こんにちわ, 世界
なお, #から行末まではコメントで, 実行時には無視されます.
エディタでファイルを編集しなくても, インラインで実行することも可能です. -e オプションを使います.
$ ruby -e 'print("Hello, World\n")' Hello, World
また, irbという対話型のrubyも用意されています. irb(main):001:0> などというプロンプトが現れるので, そこにスクリプトを記述すると即座に結果が表示されます.
$ irb irb(main):001:0> print("Hello, World\n") Hello, World ←標準出力 => nil ←irbでは戻り値も表示
2行目は 'print("Hello, World\n")' というコマンドの実行に対する戻り値を表しています. さしあたっては気にしなくていいでしょう. irbを終了するには exit です.
irb(main):002:0> exit $
ruby の基本的な使い方
以下では irb (対話型の ruby) を使って ruby の基本的な使い方を見ていきます.
型宣言は不要
Rubyには型宣言は不要です.
$ irb irb(main):001:0> a = 2 # 整数 => 2 irb(main):002:0> b = 3.5 # 実数 => 3.5 irb(main):003:0> c = "apple" # 文字列 => "apple"
"="の両側の空白は入れても入れなくてもかまいません. これらは, a, b, c という変数に 2 という整数, 3.5という実数, "apple" という文字列を代入したと考えることもできますが, 実際には 2 という整数オブジェクト, 3.5という実数オブジェクト, "apple" という文字列オブジェクトに a, b, c という名札をつけたということに相当しています.
オブジェクトはその値だけでなく型や大きさなど諸々の情報も自分で持っています.
irb(main):004:0> a # オブジェクトの値 => 2 irb(main):005:0> b.class # オブジェクトの型 => Float irb(main):006:0> c.size # オブジェクトの大きさ => 5 irb(main):007:0> 3.5.class # b.class と同じ => Float
上の class や size はメソッドと呼ばれます. オブジェクトに対して「型を述べよ」「大きさを答えよ」などとメッセージを送っていることになります. オブジェクトはそれに対して「実数だ」「5だ」などと答えてくれます.
演算
演算も当然できます. いろいろやってみてください.
irb(main):008:0> d = a * ( b**2 + 3.0e2 ) => 624.5 irb(main):009:0> e = c + "orange" => "appleorange" # 文字列の足し算は単に順に並べるだけ.
ちなみに複数の変数をいっぺんに操作することもできます.
irb(main):010:0> e,f = a*b, e+"lemon" => [7.0, "appleorangelemon"]
大文字ではじめると定数になります. 定数を書きかえようとすると警告が出ます.
irb(main):011:0> A = 3.1415927 => 3.1415927 irb(main):012:0> A = 1.7320508 (irb):22: warning: already initialized constant A => 1.7320508
シングルクォーテーション (') でくくった部分も文字列になりますが, こちら は制御文字もそのまま文字として扱います.
irb(main):013:0> print 'apple\n' apple\n=> nil # 改行されずに\nが表示される
型変換
型変換は to_s, to_i, to_f といったメソッドを使います.
irb(main):101:0> g = b.to_s => "3.5" # to_s 文字列に変換 irb(main):102:0> h = b.to_i => 3 # to_i 整数に変換 irb(main):103:0> a.to_f/3 - a/3 => 0.666666666666667 # to_f 実数に変換
整数を整数で割っても整数しか返さないので, どちらかを実数に変換しておく必要が あります.
配列
オブジェクトを順番に並べて [ ] でくくったものが配列です. 配列の中は同じ型である必要はありません.
irb(main):113:0> ary1 = [ 3, b, d-3.0, "orange"] => [3, 3.5, 621.5, "orange"] irb(main):114:0> ary1[0] => 3 # Cと同じで最初の要素が0番 irb(main):115:0> ary1[1..3] => [3.5, 621.5, "orange"] # 1番から3番まで irb(main):116:0> ary1[-1] => "orange" # 負の数はうしろから数える irb(main):117:0> ary2 = [a, ary1] => [2, [3, 3.5, 621.5, "orange"]] # 配列の中に配列があっても大丈夫. irb(main):118:0> ary2[1][3] => "orange" # ary2[1]の3番の要素
配列の要素が最初に決まっていない場合は, 配列を定義し, 配列に要素を追加していくことができます.
irb(main):001:0> ary3= Array.new => [] irb(main):002:0> ary3.push( 100 ) => [100] irb(main):003:0> ary3.push( "apple" ) => [100, "apple"]
乱数
乱数を生成するには組み込み関数の rand を使用する. 0 以外の引数を指定した場合, 0 からその値未満までの整数を生成し, 0 を指定するか引数を省略した場合は 0 以上 1 未満の実数で乱数を返す.
p rand #=> 0.2955039968 (for example) p rand(100) #=> 17 (for example)
制御構文
プログラムの流れの制御には, for, while (繰り返し), if, case (条件分岐)などが使えます. もちろんirbの中でも使えます.
irb(main):121:0> for i in 1..3 irb(main):122:1> print(i,"\n") irb(main):123:1> end 1 2 3 => 1..3
いずれも終わりを表すのは end です. プロンプトの">"の左の数字はネストの深さを表していて, ネストがなくなる3行目まではなにもおこなわれません.
irb(main):020:0> for i in 1..5 irb(main):021:1> if i == 3 then # thenはなくてもよい irb(main):022:2* print "Hello \n" irb(main):023:2> else irb(main):024:2* print "#{i} \n" # "#{..}" とすると文字型に変換できる irb(main):025:2> end irb(main):026:1> end 1 2 Hello 4 5 => 1..5
配列の各要素に対して順に処理をおこなうイテレータというものもあります.
["dog","cat","bird"].each {|i| printf("a %s\n", i) }
each は {...} (または do ... end) を引数にとるメソッドです. 配列の各要素を | | の中の変数(ここでは i )に格納し, その i に対する操作を記述します. つまり
for i in ["dog","cat","bird"] printf("a %s\n", i) end
と同じです. これだけだとあまりありがたみが感じられないかもしれませんが, イテレータにはいろいろなものがあり, より直接的にループを記述することができます. for を使うより便利なことが多いです.
(1..10).each {|i| printf( "%02d\n", i ) } 10.times {|i| # 10回繰り返し printf( "%02d\n", i ) } 10.times do # 10回繰り返し print "hoge" end loop do # 無限ループ break if STDIN.gets=="\n" # 空行を入力すればループを抜ける end loop do break if /^$/ =~ gets # 上と同じ(/.../は正規表現, =~は正規表現とマッチしているかどうか, getsはSTDIN.gets end
注:イテレータ(ブロック)は, 変数のスコープ(有効範囲)を作ります. 次のよ うなスクリプトはエラーになります.
(1..10).each{|i| b = i } puts b # {…}の外では b が存在しないのでエラーになる
エラーを避けるには
b = 0 (1..10).each{|i| b = i } puts b # 10
のようにします.
数学関数 (モジュールの例)
数学関数は, Mathモジュールを使います. Mathモジュールの中に, 三角関数などのメソッドや円周率などの定数が定義されています.
irb(main):027:0> a = Math::cos(0) => 1.0 irb(main):028:0> b = Math::PI => 3.141592653589793
include文を使うと, それ以降は"Math::"の部分が不要になります.
irb(main):029:0> include Math => Object irb(main):030:0> c = cos(PI) => -1.0
日付と時刻 (クラスの例)
日付や時刻を扱うには, DateTimeクラスを使うと便利です. DateTimeクラスの定義は起動時に読み込まれていないので, まず
irb(main):032:0> require "date" => true
とします. これで定義が読み込まれます. DateTimeクラスのオブジェクトを作るには
irb(main):033:0> sakki = DateTime.new(2010,3,8,9,30)
とします. およそどのクラスでも一般に new というのが新しいオブジェクトを作る メソッドです. 他に
irb(main):034:0> ima = DateTime.now # 現在 irb(main):035:0> itsuka = DateTime.parse("2003-04-05") # 文字列を解釈して作成
といったやり方もあります.
DateTimeクラスには足し算引き算他さまざまなメソッドが定義されています.
irb(main):037:0> sakki.year # 40日後は何日か. => 2010 irb(main):038:0> (sakki + 40).day # 差の日数(121411/48日) => 17 irb(main):039:0> sakki - itsuka => (121411/48) irb(main):040:0> (sakki>>1).to_s # 1ヶ月後を文字列にする => "2010-04-08T09:30:00+00:00" irb(main):041:0> sakki.strftime("%H:%M (%y/%m/%d)") # 好きなフォーマットの文字列にする => "09:30 (10/03/08)"
手続き定義
def を使ってメソッドを定義することにより, 他の言語と同じような形で 手続きを定義できます.
def wa(a,b,c) d = a+b+c return d # 戻り値の指定. なければ最後の文の戻り値が返される. end e = wa(3,4,6) # 定義前に実行することはできない.
テキストデータの書き出し
ファイルの入出力には File クラスを用います.
file1 = File.open("test.txt","w") # "w"を付けると書き込み可能で開く. file1.print("Hello, World\n") for i in 1..10 file1.printf( "%02d %02d\n", i, i*2 ) end file1.puts("Hello, Hello, World") # 改行付きで出力される file1.close
file1がファイル"test.txt"に対応するFileクラスのオブジェクトになります. これに print printf puts などのメソッドを作用させるとファイルに書き出されます. puts は引数を1行分として書き出すので最後に必ず改行が入るようになっています. print や printf では改行も自分で制御します. 実際に書き出されているか確かめてみましょう.
テキストデータの読み込み
ファイルをオープンするには組込み関数のopen, File::openメソッドを, ファ イルの読み込みは組込み関数のIO#eachメソッド, IO#getsメソッドを使用する ことができます.
# # IO#eachを使う例 # f = open("foo") f.each {|line| print line} f.close # # IO#getsを使う例 # f = open("foo") while line = f.gets print line end f.close # # IO#each_lineを使う例 # f = open("foo") f.each_line {|line| print line } f.close
NArray を使って配列演算
Rubyに標準装備されている配列(Array)は, オブジェクトを順番に並べたものであり, これもまた1つのオブジェクトです. 上の例にあったように, 配列の要素は同じ型である必要はなく 任意のオブジェクトを格納できるという柔軟なものなので, その分計算速度は犠牲になっています. 扱うデータが数値である場合には, NArray というクラスパッケージを用いると高速に計算できます. さらに, 平均や標準偏差といった統計処理も簡単に行うことができます.
詳しくはNumo::NArray 概要を適宜参照してください.
NArray クラスのつくりかた
NArrayクラスを用いるには, まず
require "numo/narray"
とします. これでNArrayクラスの定義が読み込まれます. 新たに倍精度実数型の配列を生成するには, Numo::DFloat.new(大きさ,大きさ,...) とします. 倍精度実数配列を作るには例えば以下のようにします. ".seq" をつけると通し番号で初期化されます.
irb(main):008:0> ary1 = Numo::DFloat.new(3,4).seq => Numo::DFloat#shape=[3,4] [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]] irb(main):009:0> ary2 = Numo::DFloat[ 2, 3, 4.5, 8 ] => Numo::DFloat#shape=[4] [2, 3, 4.5, 8] irb(main):017:0> ary3 = Numo::DFloat[ [2, 3, 4.5, 8], [1, 2] ] => Numo::DFloat#shape=[2,4] [[2, 3, 4.5, 8], [1, 2, 0, 0]]
shape, ndim, class, size などのメソッドも使えます.
irb(main):010:0> ary1.shape => [3, 4] irb(main):011:0> ary1.ndim => 2 irb(main):012:0> ary1.class => Numo::DFloat irb(main):013:0> ary1.size => 12
また, 通常の配列(Array)とNArrayの間で型変換するには
irb(main):058:0> ary4 = [ 2, 3, 4.5, 8 ] => [2, 3, 4.5, 8] irb(main):059:0> Numo::NArray[ary4] => Numo::DFloat#shape=[1,4] [[2, 3, 4.5, 8]]
NArray を通常の配列 (Array) へ変換する場合は以下のようにします.
irb(main):019:0> ary5 = ary2.to_a => [2.0, 3.0, 4.5, 8.0]
NArrayでは, 例えば中に1つでも実数が含まれていれば実数の配列となり, 要素はすべて実数になります.
要素番号
インデックスはArrayやC言語と同じで, 最初の要素番号は0, 最後の要素番号は要素数-1です. 添字の付け方に注意してください.
irb(main):031:0> ary1 => Numo::DFloat#shape=[3,4] [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]] irb(main):026:0> ary1[0,0] => 0.0 irb(main):027:0> ary1[1,1] => 5.0 irb(main):029:0> ary1[0..2,0] => Numo::DFloat(view)#shape=[3] [0, 4, 8] irb(main):030:0> ary1[0,0..3] => Numo::DFloat(view)#shape=[4] [0, 1, 2, 3] irb(main):032:0> ary1[0,0..-1] => Numo::DFloat(view)#shape=[4] [0, 1, 2, 3]
算術演算
演算は要素ごとにやってくれます. +, -, *, /, % などが使えます.
irb(main):033:0> ary10 = Numo::DFloat[ 2, 3, 4, 5 ] => Numo::DFloat#shape=[4] [2, 3, 4, 5] irb(main):034:0> ary11 = Numo::DFloat[ 9, 8, 7, 6 ] => Numo::DFloat#shape=[4] [9, 8, 7, 6] irb(main):035:0> ary10 + ary11 => Numo::DFloat#shape=[4] [11, 11, 11, 11] irb(main):036:0> ary10 - ary11 => Numo::DFloat#shape=[4] [-7, -5, -3, -1]
統計量
次の統計メソッドが定義されています. メソッド名を見れば何をしているか想像つくでしょう.
sum prod mean stddev var rms min min_index max max_index minmax cumsum cumprod sort sort_index median
たとえば, 以下のように計算できる.
irb(main):033:0> ary10 = Numo::DFloat[ 2, 3, 4, 5 ] => Numo::DFloat#shape=[4] [2, 3, 4, 5] 合計 irb(main):037:0> ary10.sum => 14.0 平均 irb(main):038:0> ary10.mean => 3.5 標準偏差 irb(main):039:0> ary10.stddev => 1.2909944487358056