或るプログラマの開発日記

日々の勉強したことの備忘録なんかに使っていきます

Rubyで乱数生成

Rubyの乱数生成メモです。

rand関数

Rubyで乱数生成をするにはrandメソッドを使います。

10.times do
  puts rand(1000)
end

このプログラムは、0~999までの範囲の乱数を10回出力します。

ただ、この乱数は擬似乱数と呼ばれるものであり、乱数生成に使われる種(シード)を元に算出されている数になりますので、純粋にランダムな数が生成されているわけではないということに注意が必要です。

擬似乱数の偏りについて説明しだすと長くなりすぎるので詳細はWikipediaのほうを参照。

擬似乱数 - Wikipedia


因みに、srandメソッドを使うことで乱数の種を明示的に与える事が可能です。

srand(3)
10.times do
  puts rand(1000)
end

実行結果

874
664
249
643
952
968
256
789
659
714

種を指定した方のプログラムは何回実行しても同じ結果を返します。

SecureRandomクラス

所謂、安全な乱数を生成したい場合はSecureRandomクラスを使います。

require 'securerandom'
p SecureRandom.random_number(10000)
p SecureRandom.hex(16)
p SecureRandom.base64

乱数以外にも、ランダムな文字列、base64文字列の生成に使えます。

ただし、実行速度は擬似乱数のほうと比べると結構遅いです。

Rubyで書式付き出力を行う

Rubyの書式付き出力に関するメモ。

Rubyの書式付き出力

C言語なんかでもみるsprintfメソッドを使うやり方と、%演算子を使うやり方があります。先ずは%演算子を使う例を見てみます。

プログラム

(1..10).each do |n|
  puts "%03d" % n
end

実行結果

001
002
003
004
005
006
007
008
009
010

このプログラムの"%03d" % nは、sprintf("%03d", n)と同じ意味になります。

個人的には、%の演算というと、どうも剰余を求めている様な感じがするので違和感ありまくりでしたが、演算子が文字列にかかっているか、数値にかかっているかの違いと理解すれば良いのでしょうか。

因みに、複数の書式を一度に扱う例は以下の通り。

puts "100 to bin ->%b  ,oct->%o  ,hex->%X" % [100,100,100]
#=>100 to bin ->1100100  ,oct->144  ,hex->64

puts sprintf("100 to bin ->%b  ,oct->%o  ,hex->%X", 100,100,100)
#=>100 to bin ->1100100  ,oct->144  ,hex->64

雑感

CやJavaに慣れてるとRubyのプログラムは%:とか@が普段見慣れない使われ方をするので混乱しがちです。ま、丁寧に個々の意味を読み解いていくしかないのでしょうな。

Rubyのsortメモ

Rubyのsortに関するメモです。

sortメソッド

配列をソートするには、sort(もしくはsort!)メソッドを使います。後ろにブロック処理を記述することで、比較方法を定義する事が出来ます。ここでは昇順でソートする方法と降順でソートする方法を記載します。

p [5,3,7,4,9,0,1,8,2,6].sort
#=>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

p [5,3,7,4,9,0,1,8,2,6].sort{|a, b| a <=> b }
#=>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  
p [5,3,7,4,9,0,1,8,2,6].sort.reverse
#=>[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

p [5,3,7,4,9,0,1,8,2,6].sort{|a, b| b <=> a }
#=>[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

因みに、ブロックの中で出てきた<=>は比較演算子と呼ばれるもので、左右の項の大小関係により、0,1,-1が返却されます。

p 1 <=> 1 #=> 0
p 1 <=> 0 #=> 1
p 0 <=> 1 #=> -1
p 2 <=> 0 #=> 1
p 0 <=> 2 #=> -1

sort_byメソッド

ブロック処理の戻り値を元にソートすることを前提としたのがsort_byメソッドです。以下の例のように、アルファベット順でなく、文字数でソートしたい時などに使えます。

langs = ["Java", "C", "Python", "C++", "Ruby", "Basic"]
p langs.sort_by{|s| s }
#=>["Basic", "C", "C++", "Java", "Python", "Ruby"]

p langs.sort_by{|s| s.size }
#=>["C", "C++", "Java", "Ruby", "Basic", "Python"]

Rubyでhashから値を取る方法のメモ

Rubyでhashを使ってて、Javaとかとは勝手が違っていたところで結構ハマッたので、調べた情報をメモ。

keyが文字列かシンボルか?

Rubyのhashはkeyとして文字列はもちろん、シンボルをkeyとして使うことも出来ます。例として、文字列、シンボルそれぞれをkeyとしたhashから値を取得するプログラムを書いてみます。

strhash={"key1" => "value1", "key2" => "value2", "key3" => "value3"}
symbolhash={key1: "value1", key2: "value2", key3: "value3"}
p strhash["key1"] # => "value1"
p strhash[:key1]  # => nil
  
p symbolhash["key1"]# => nil
p symbolhash[:key1] # => "value1"

もちろん、文字列とシンボルは中身が全然異なるので、それを混同するとおかしなことになります。keyが何の型かを認識しておかなければなりません。

fetchメソッドの仕様

先の例では[]を使って値を取得していましたが、fetchメソッドを使って値を取得することも出来ます。[]を使うのと、fetchを使うのとでは、hashから値が取れなかった時の扱いに大きな違いがあります。

単純なfetchメソッド

keyのみを引数とするfetchメソッドは、値が取れなかったときに例外が発生します。

symbolhash={key1: "value1", key2: "value2", key3: "value3"}
p symbolhash.fetch(:key1) # => "value1"
p symbolhash.fetch(:key4) # => `fetch': key not found: :key4 (KeyError)

値が絶対に取得できる前提で使うにはいいのかもしれませんね。

デフォルト値付きfetch()

第2引数にデフォルト値を渡すと、値が取れなかったときにデフォルト値が返却されます。

symbolhash={key1: "value1", key2: "value2", key3: "value3"}
p symbolhash.fetch(:key1, "not found") # => "value1"
p symbolhash.fetch(:key4, "not found") # => "not found"

[]で取るのと、fetch(key, nil)とは同じということですね。

ブロック付きfetch()

ブロックを渡すと、値が取れなかったときにブロックの値を評価した値が返却されます。

symbolhash={key1: "value1", key2: "value2", key3: "value3"}
p symbolhash.fetch(:key1){|key| key.to_s + " not found"} # => "value1"
p symbolhash.fetch(:key4){|key| key.to_s + " not found"} # => "key4 not found"

うーん。。正直使いどころが良く分からんが、まーこういう使い方も出来るということですね。

参考URL

stackoverflow.com

RubyでStreamから渡された数値群をFixnumに変換する方法

CodeIQ、paiza等で出るプログラミングの問題では、標準入力から渡された数値データを処理する事が多いですが、標準入力経由だと基本文字列として受け取る為、計算に利用するにはプログラム内部で数値型に変換する必要があります。

この変換処理をいちいち書くのが結構おっくうだったりするのですが、Rubyでは結構簡単に処理を記述することができたので、ここにメモしておきます。

文字で与えられた数値群を一括変換

例として、標準入力から与えられた数値群を全て足した値を標準出力に出力するプログラム書いてみます。

先ずは、ダメな例から。

(a, b, c)=DATA.gets.split
puts a + b + c

__END__
10 20 30

こいつを実行すると、

102030

という結果になります。単に文字を連結してるだけですね(^^;)


とりあえず動かす為の修正方法として、

puts a.to_i + b.to_i + c.to_i

とすれば目先要件は満たせるでしょうが、如何にも書き方が野暮ったいという感じがします。


to_iの処理を何回も書かないような記述方法がこれ。

(a, b, c)=DATA.gets.split.map(&:to_i)
puts a + b + c

__END__
10 20 30

実行すると、

60

というわけで、それぞれ問題なく数値型に変換されています。

map(&:to_i)のやっていること

初めてこのような記述を見て、何がなんだか訳分からん状態だったので、自分なりに調べた内容でこれを要約すると、
:to_iシンボルに対するto_procメソッドの結果として返ってきたProcオブジェクトをブロックとしてmapメソッドに渡す。
という事になります。


ちょっとややこしいので細かく分解してみましょう。


先ず、mapメソッドのやっている事。

mapメソッド

mapメソッドは、要素の数だけ繰り返しブロックを実行し、ブロックの戻り値を集めた配列を作成して返します

http://ref.xaio.jp/ruby/classes/array/map

次に、(&:to_i)の部分の、「&」の意味。

ブロックの部分だけを先に定義して変数に保存しておき、後からブロック付きメソッドに渡すことも出来ます。 それを実現するのが手続きオブジェクト(Proc)です。 それをブロックとして渡すにはブロック付きメソッドの最後の引数として `&' で修飾した手続きオブジェクトを渡 します。

https://docs.ruby-lang.org/ja/2.2.0/doc/spec=2fcall.html#block

ま、mapに手続きオブジェクトを渡しているというのは確かなようです。


最後に、「&」の後に続く:to_iの意味。

これはSymbolと呼ばれるオブジェクトです。しかし「&」に続く物としては手続きオブジェクトが期待されているので型が合いません。
そのためSymbolが持つto_procメソッドで暗黙的にProcオブジェクトに変換されているのです。

https://docs.ruby-lang.org/ja/2.2.0/class/Symbol.html#I_TO_PROC

以上が、map(&:to_i)のやっている事になります。

雑感

今回のケース、正直ソースの見た目も内部でやっている事も大分ややこしいんですが、to_procが省略されているという事が発見出来れば理解するのも難しくないかなぁという感じです。

参考URL

stackoverflow.com

Rubyにおける「真」と「偽」の判定

Ruby及びその他の言語に於ける真と偽の扱いのメモ。

「真」と「偽」の扱い

if文やwhile文での条件判定に使う「真」と「偽」の扱いはプログラム言語により様々だったりします。

例えばC言語ではint型の0が「偽」であり、それ以外が「真」です。Java言語ではプリミティブ型であるbooleanが用意されており、trueが「真」、falseが「偽」として扱われます。

では、Rubyはどうなの?ということで調べて見ますと、Rubyではfalseとnilが「偽」、それ以外が「真」として扱われます。

実際の挙動を見てみましょう。

プログラム

if nil
  puts "nil is true"
else
  puts "nil is false"
end

if false
  puts "false is true"
else
  puts "false is false"
end

if 0
  puts "0 is true"
else
  puts "0 is false"
end

if 1
  puts "1 is true"
else
  puts "1 is false"
end

実行結果

nil is false
false is false
0 is true
1 is true

このように、0が「偽」扱いにはならないという点はRubyを使う上で留意する必要がありますね。

参考URL

その他の言語はどうだっけ?という事で調査してみたら、上手く纏めていただいているページがありました。非常に参考になります。

blog.mirakui.com

Rubyプログラムをプロファイラで計測する

今回は、Rubyのプロファイルを取得する機能についてのメモ。

プロファイラの実行

Rubyでは標準でプロファイルを取る機能が用意されています。ここでいうプロファイルとは、どの処理にどれ位時間が掛かってるかや、どの処理が何回呼ばれたかという分析結果です。rubyコマンドに -r profile オプションをつけて実行することで、プロファイルを取る事が出来ます。

ruby -r profile test.rb

因みに私はeclipseから実行することが主なので、eclipseから実行する場合の手順ものせておきます。

[Run As]->[Run Configurations ...]から、ArgumentsタブのInterpreter argumentsに -r profileオプションをつけます。

f:id:sishow03:20170420001724j:plain


では、物は試しということで、簡単なfizzbuzz問題のプログラムのプロファイルを取ってみましょう。

プログラム

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

実行結果

1
2
Fizz
4
Buzz
.
.
中略
.
.
Fizz
97
98
Fizz
Buzz
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  0.00     0.00      0.00        1     0.00     0.00  TracePoint#enable
  0.00     0.00      0.00        3     0.00     0.00  Thread.current
  0.00     0.00      0.00        1     0.00     0.00  Mutex#lock
  0.00     0.00      0.00        1     0.00     0.00  MonitorMixin#mon_enter
  0.00     0.00      0.00        1     0.00     0.00  Kernel#respond_to_missing?
  0.00     0.00      0.00        1     0.00     0.00  Kernel#respond_to?
  0.00     0.00      0.00        1     0.00     0.00  Gem.suffixes
  0.00     0.00      0.00        4     0.00     0.00  Gem.find_unresolved_default_spec
  0.00     0.00      0.00        1     0.00     0.00  Array#each
  0.00     0.00      0.00        1     0.00     0.00  Gem::Specification.unresolved_deps
  0.00     0.00      0.00        1     0.00     0.00  MonitorMixin#mon_check_owner
  0.00     0.00      0.00        1     0.00     0.00  Mutex#unlock
  0.00     0.00      0.00        1     0.00     0.00  MonitorMixin#mon_exit
  0.00     0.00      0.00        4     0.00     0.00  IO#set_encoding
  0.00     0.00      0.00        2     0.00     0.00  IO#sync=
  0.00     0.00      0.00        1     0.00     0.00  Kernel#gem_original_require
  0.00     0.00      0.00        1     0.00     0.00  Kernel#require
  0.00     0.00      0.00      261     0.00     0.00  Fixnum#%
  0.00     0.00      0.00      261     0.00     0.00  Fixnum#==
  0.00     0.00      0.00       53     0.00     0.00  Fixnum#to_s
  0.00     0.00      0.00      200     0.00     0.00  IO#write
  0.00     0.00      0.00      100     0.00     0.00  IO#puts
  0.00     0.00      0.00      100     0.00     0.00  Kernel#puts
  0.00     0.00      0.00      100     0.00     0.00  nil#
  0.00     0.00      0.00        1     0.00     0.00  Range#each
  0.00     0.00      0.00        1     0.00     0.00  TracePoint#disable
  0.00     0.01      0.00        1     0.00    10.00  #toplevel

このような感じで、実行結果の後にプロファイルが出力されます。今回は単純なプログラムなので時間計測はほぼ意味が無いですが、剰余演算子の処理が何回行われたかというような情報は得られます。

各項目の意味

それぞれがどのような意味かは、リファレンスマニュアルに詳しいので引用します。

  1. 全体時間のパーセンテージ
  2. 全体時間の総和(単位は秒)
  3. 正味時間の総和(秒)
  4. 呼び出された回数
  5. 1回の呼び出し当たりの平均正味時間(ミリ秒)
  6. 1回の呼び出し当たりの平均全体時間(ミリ秒)
  7. メソッド名
https://docs.ruby-lang.org/ja/latest/library/profile.html

その他のプロファイラ

標準で利用できるprofile以外にも、ruby-profという軽量なプロファイラ等いろいろあるようなので使って見ようと思います。