Day 2 ~ 13: Ruby 認定試験による勉強

post on
post cover image

ソースコードの文字コードをUS-ASCIIに設定のマジックコメント

# 1. coding: us-ascii
# 2. encoding: us-ascii
# 3. -*- charset: us-ascii -*-
# 4. CODING: US-ASCII

1,2,4は同義で、正解。3はPython。

例外処理(begin rescue ensure end

Wikipediaによると

プログラムの上位の処理から呼び出されている下位の処理で継続不能、または継続すれば支障をきたす異常事態に陥ったとき、制御を呼び出し元の上位の処理に返し安全な状態になるよう回復処理をすること。

begin
  # 例外が起こりうるコード1
rescue => # 変数(例外オブジェクトの代入)
  # 例外が起きた場合のコード2
ensure
  # 例外の有無に関わらず、実行するコード3 
end

1で例外が起きなかったら、表示結果は1且つ3の表示結果、起きた場合は2且つ3の表示結果となる。
例外処理コードとして、ensureが用いられないパターンもある。
その他、rescueの中でretryを用い、beginが成功するまで繰り返す処理がる。(無限ループ注意)

定数と変数

下コードの実行結果は『10と表示された後、警告が表示され100と表示される。』

MAX=10
print MAX
MAX=100
print MAX

Rubyにおいて、アルファベット大文字から始まる識別子(ABCやAbc)は定数である。
他言語では定数を再定義しようとすると、警告が出て、結果、再定義できない。
Rubyにおいては、警告が出たのち、そのままデータがオーバーライトされる

可変長引数

def foo(*a)
  p a
end
foo(1,2,3)
#実行結果 [1,2,3]

*を1個付けると、引数を複数指定でき、引数は配列として受け取られる。
*を2個付けると、オプション引数となり、Hashとして受け取られる。

範囲オブジェクトとeach

.to_i

文字列を10進数の表現と見なして整数に変換します。

#引数baseを取ることもでき、その引数で何進数かを示す。
#デフォルト値は10であり、引数指定しない場合は10進数となる。
変数.to_i(2)

範囲オブジェクト

def hoge
  x = 0
  (1...5).each do |i|
    x += 1
  end
  puts x
end
hoge
#実行結果 4

まず『数A...数B』に関して、これはAからBまで繰り返すの意。ただし、Bは含まれない。
そのため、『1...5』は、1から4までの4回分繰り返す。
一方で、『1..5』は5を含み、1から5までの5回分繰り返す。
因みに、『1..5』『101..105』『2001..2005』だろうと5回分。

upto

money = 1000
オブジェクト.upto(max) do |i|
  実行処理
end
 
money = 100
1.upto(3) do |i|
  money = money * 1.1
end
puts money.to_i

uptoメソッドは、変数に「対象オブジェクトが持つ数値」から「max」までを順に代入しながら、処理実行。
1回繰り返す毎に1ずつ数値は増加します。(ここでは1から3までの3回。『1..3』と同義。
また、downtoメソッドもあり、これは1回繰り返すごとに1ずつ数値が減少する。
timesメソッドも参照すべし

step

オブジェクト.step(limit, stepno) do |変数|
  実行する処理1
  実行する処理2
end

はじめに、stemnoを『数値間隔』とするとわかりやすい。
対象オブジェクトを持つ数字から順に代入しながら、処理を実行。
1回繰り返すごとに、stepnoで指定した数値間隔ごとに、数値が増加する。

範囲オブジェクト、uptoメソッドまとめ

money = 1000
rate = 1.1
2001.upto(2004) do |i|
  money = money * rate
  puts "I got #{money.to_i} in #{i}."
end
#実行結果
# I got 1100 in 2001.
# I got 1210 in 2002.
# I got 1331 in 2003.
# I got 1464 in 2004.

これは、下とも書ける

money = 1000
rate = 1.1
(2001..2004).each do |i|
  money *= rate
  puts "I got #{money.to_i} in #{i}."
end

4日目

変数、定数いろいろ

  • ローカル変数
    • アルファベット小文字または`_'で始まる識別子
  • グローバル変数
    • $で始まり、宣言が必要なく、プログラムのどこからでも参照できる。
    • 初期化されていないグローバル変数を参照した場合、値はnil。
  • インスタンス変数
    • @で始まり、特定の オブジェクトに属する。
    • そのクラスま たはサブクラスのメソッドから参照できます。
    • 初期化されていないインスタンス変数を参照した場合、値はnil。
  • クラス変数
    • @@で始まり、クラス定義 の中で定義される
    • クラスの特異メソッド、インスタンスメソッドなどから参照/代入ができる。
  • 定数
    • アルファベット大文字で始まる。
    • 他の言語では『定数』なので、再定義しようとしても、警告が出て、再定義できない。
    • Rubyでは、再定義しようとすると、警告が出るが、再定義できてしまう。

super

親クラスのメソッドを呼び出す

class User 
  attr_accessor:say
  def initialize
    @say = "Hello"
  end
end
class Oriver < User
  def initialize
    super
  end
end

oriver = User.new
puts oriver.say
#実行結果:Hello
#この時、superメソッドは親クラスのUserから、@sayを呼び出している

attr_accerssor(attr_readerとattr_writer)

  • attr_accerssorはゲッターとセッターの機能があるアクセスメソッド
  • インスタンス変数の値はクラス内からしか取得出来ない。
  • クラス外からインスタンス変数を取得更新するには、ゲッター、セッターが必要
    • ProgateのPHPの方なら説明がちゃんとあった。

include (モジュール名, モジュール名, ...)

クラスやモジュールに、他のモジュールをインクルードする。
引数にはモジュールを指定し、上の様に複数指定することができる

Math module

浮動小数点演算をサポートするモジュール.

#円の面積
include Math
def area r
  return r * r * PI
end

#球の体積
def volume r
  return (4/3) * r * r * r * PI
end 

#πの値
puts PI #結果:3.141592653589793
area(2) #結果:12.566370614359172
volume (2)  : 25.132741228718345

これは便利。


7日目

演算子のオーバーライド

Ruby の場合、演算子の多くがただのメソッドとして定義。

再定義できる演算子

|  ^  &  <=>  ==  ===  =~  >   >=  <   <=   <<  >>
+  -  *  /    %   **   ~   +@  -@  []  []=  ` ! != !~

再定義不可の演算子

演算子の組合せである自己代入演算子は再定義できない。

=  ?:  ..  ...  not  &&  and  ||  or  ::

演算子の定義方法

# 二項演算子
def +(other)                # obj + other
def -(other)                # obj - other

# 単項プラス/マイナス
def +@                      # +obj
def -@                      # -obj

# 要素代入
def foo=(value)             # obj.foo = value

# [] と []=
def [](key)                 # obj[key]
def []=(key, value)         # obj[key] = value
def []=(key, key2, value)   # obj[key, key2] = value

# バッククォート記法
def `(arg)                  # `arg` または %x(arg)

メソッドのオーバーライドと比較演算子

##比較演算子と<<  :問題
class Employee
  attr_reader :id
  attr_accessor :name
  
  def initialize id, name
    @id = id
    @name = name
  end
  
  def to_s
    return "#{@id}:#{@name}"
  end
  #ここに代入する式を選択して下さい。
end

employees = []
employees << Employee.new("3","Tanaka")
employees << Employee.new("1","Suzuki")
employees << Employee.new("2","Sato")
employees.sort!
employees.each do |employee| puts employee end

# 実行結果
1:Suzuki
2:Sato
3:Tanaka

# 選択肢
# 1 (答え)
def <=> other
  return self.id <=> other.id
end

比較演算子 <=>

1 2
a < b -1
a == b 0
a > b 1
比較不可 nil

<< とは

<<<演算子(メソッド)は、左辺の配列(レシーバ)の末尾に右辺のオブジェクトを要素として加えます。

#例
animals = ["dog", "cat", "mouse"]
animals << "pig"
p animals
["dog", "cat", "mouse", "pig"]

&& & and と || | or の違い

#問題
a = [1,2,3,4]
b = [1,3,5,7]
#ここに代入する式を選択して下さい。
c = XXXX
c.each {|i| print i, " " }
#出力結果
1  3
#選択肢
1. a+b ,2. a-b  ,3. a & b  ,4. a && b ,  5. a | b , 6. a || b
#解答 3
  • &&演算子
    • 左辺の評価結果がfalseの場合は、右辺を評価せずに次の処理に進む
  • || 演算子
    • 左辺の評価結果がtrue の場合は、右辺を評価せずに次の処理に進む
  • |演算子と&演算子
    • 左辺の評価結果に関係なく、右辺を評価する

範囲オブジェクト

#範囲オブジェクト等:問題
a = [1,2,3,4]
#ここに代入する式を選択して下さい。
a.each do |i|
  print i, " "
end
#実行結果
1 2 3

# 選択肢
1. a[0..3]  ,2. a[0..-2]  ,3. a[0...-2]  ,4. a[0...-3] ,
5. a[3,0]  , 6. a[0,3]    ,7. a[2,0]       ,8. a[0,2]
# 答えは2と6

配列のメソッド

適切なものを選べ

# 問題選択肢
1. find_allとselectは同じ動作をする。
2. mapとcollectは同じ動作をする。
3. findとselectは同じ動作をする。
4. firstは先頭要素を削除し、その要素を返す。
5. concatは非破壊的メソッドである。
6. concat!は破壊的メソッドである。

#解答
1と2

select と find_all

同じ動作を、条件に合う配列をそのまま出力

#select
[1, 2, 3, 4, 5].select{ |v| v % 2 == 1 }
=> [1, 3, 5]
#find_all
[1, 2, 3, 4, 5].find_all{ |v| v % 2 == 1 }
=> [1, 3, 5]

map と collect

同じ動作をし、条件にある配列をtrue or falseで出力

#map
[1, 2, 3, 4, 5].map{ |v| v % 2 == 1 }
=> [true, false, true, false, true]
#collect
[1, 2, 3, 4, 5].collect{ |v| v % 2 == 1 }
=> [true, false, true, false, true]

find

findは先頭要素だけ出力

#find
[1, 2, 3, 4, 5].find{ |v| v % 2 == 1 }
=> 1

破壊的メソッドconcat

concat!は定義されていない

val = [ "a", "b" ]
c=> ["a", "b"]
val.concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]
=> ["a", "b", "c", "d"]l
puts val
a
b
c
d

最後、valの値が変化している所、、要注意

zip[array]

コード結果を選べ

a1=%w(a b)
a2=%w(x y)
a3=a1.zip(a2)
p a3.first

# 選択肢
1. "a"  ,2. ["a"]    ,3. ["a", "x"]  ,4. ["a", "b"]  ,5. 例外が発生する。
# 解答

%w( )

配列を作る。配列の要素はスペース区切りで指定する。
式の展開はされない。

zip array

instance method Array#zip

zipメソッドは、配列の要素を引数の配列other_arrayの要素と組み合わせ、配列の配列を作成して返します。行と列を入れ替えるが、足りない要素はnilで埋められ、余分な要素は捨てられます。

arr1 = [1, 2, 3]
arr2 = [4, 5]
arr3 = [6, 7, 8, 9]
p arr1.zip(arr2, arr3)
[[1, 4, 6], [2, 5, 7], [3, nil, 8]]

slice()

実行結果をかけ

a = [1,2,3,4,5]
p a.slice(1,3)

#答え

slice()

要参照

sliceメソッドは、[]メソッドの別名です。配列から引数で指定した位置の要素を取り出して返す。

equal

実行結果を書け

a = "abc"
b = "abc"
print a.eql? b
print a.equal? b
print a == b

# =>
# true  false  true

eql?

ハッシュの内部で「同じキーかどうか」を調べるために使われるメソッドで、今回はレシーバabcが引数abcと同じかどうか調べている

eqal?(object)

レシーバobjと引数other_objが同じオブジェクトならtrue、別のオブジェクトならfalseを返す。
objent絡みなので、変数名が違うと、falseを返すのだろう。。。?

型の取り扱い:エラーにならないものを選べ

select

  1. puts 5 + "Hello"
  2. puts "Hello" + 5
  3. puts "Hello" * 5
  4. puts 5 * "Hello"

integerとstring

勘違いしていた
例えば、puts hoge + "ほげ"であっても、hogeが整数型の変数なら、hogeほげと返す

concatとchopとchomp:実行結果を書け

s1 = "Hoge"
s2 = "Fuga"
s1.concat(s2)
s1.chop
s1.chomp
s1 + s2
puts s1

# => ?

concat

破壊的メソッド。<< や pushに似ている

chop

文字列の末尾から1文字を取り除いた新しい文字列を返す。
\r\n で終わっている場合だけは、 \r\n の2文字を取り除きます。

chomp

文字列の末尾の改行文字を取り除いた新しい文字列を返す。
改行文字は"\n"、"\r\n"、"\r"のどれでも取り除きます

7日目の流れ

# irb
s1 = "Hoge"
s2 = "Fuga"

s1.concat(s2)
# .c=> "HogeFuga"
# chopでs1末尾のeが取り除かれる
s1.chop
# => "HogeFug"
# s1に改行文字は含まれていない
s1.chomp  
# => "HogeFuga"
# 文字型同士の和は可能
s1 + s2
# => "HogeFugaFuga"
# concatの破壊的性質により、s1.concat(s2)の時点で、s1がHogeFugaに。
puts s1
# HogeFuga

[]メソッド

s = "123456789"
p s[1,4]

# =>
# "2345"

まず、範囲オブジェクトの類だと思っていた。

要参照: [] (Array)

slice()の別名

Hashクラス

select

  1. {}で空のHashオブジェクトを生成できる。
  2. []で空のHashオブジェクトを生成できる。
  3. invertでキーと値を入れ替えることができる。
  4. keyに対応する値を取り出すメソッドとして、haskey?(key)、key?(key)、get key(key)などが用意されている。
  5. すべての要素を削除するには、delete_allを使用する。

=> ans
3と2(答えを忘れた。後でまた調べる

Hashクラス

ハッシュオブジェクトの元になっているクラス

[]

[]メソッドは、配列から引数で指定した位置の要素を取り出して返します。引数には、整数(位置)、整数2つ(位置と数)、範囲を指定できます。

{}

Hash作成

invert

キーを値に、値をキーにしたハッシュを作成

key

has_key?メソッドは、ハッシュが引数keyと同じキーを持っていればtrue、なければfalseを返します。
key?メソッド、include?, member?メソッドは、has_key?の別名

delete_all

検索でdelete hashはヒットするが、delete_all hash はヒットしない

Hashクラス

select uncorrect

  1. deleteはキーを指定してキーと値の組を削除する。
  2. removeはキーと値の組を削除する。
  3. fetchは与えられたキーに関連付けられた値を返す。
  4. clearはハッシュの要素を全て削除する。

ans => 1, 4

delete

ハッシュから引数keyと同じキーを探して、キーと値を削除。レシーバ自身を変更するメソッド

fetch

ハッシュから引数で指定したキーの値を取り出して返します。[]メソッドと機能は同じ。だがキーが存在しないときの動作が異なる

clear

キーと値をすべて削除し、ハッシュを空にします。レシーバ自身を変更するメソッド

Hashクラス

実行結果をかけ

#{} の問題
v = {}
v.class
#出力答え Hash

Hashクラス

実行結果をかけ

#invert array : 問題
v = {:v1 => 1, :v2 => v}
v.invert
#出力答え {1=>:v1, nil=>:v2}

invert

既に上で記述済み

%等々

回答を選択しから選べ

member = [10, "Tanaka"]
print "ID:%2d Name:%s" #ここに代入する式を選択して下さい。  
member
# 実行結果
ID:10 Name:Tanaka
# 選択肢
1. ,   ,2. +
3. %    ,4. .format

#答え %

%dと%s,%

%d

数字を文字列にしている

sprintf("%d", 4);
=> "4"

# %2d 2桁の文字列を返す
sprintf("%2d", 4);
=> " 4"

# %02d 2桁の文字列を返す。桁数が足りない場合は、前に0を追加。
sprintf("%02d", 4);
=> "04"

%s

シンボル:を付ける。式の展開はされない。

Hashクラス

適切な選択肢を

#配列、シンボル 問題
h = #ここに代入する式を選択して下さい。
p h
#選択肢
1. {a:1,b:2,c:3}   、2. {a=1,b=2,c=3}
3. Hash[:a, 1, :b, 2, :c, 3]    、4. {:a1,:b2,:c3}
#実行結果
{ :a => 1, :b => 2, :c => 3 }

#答え 4

8日目

## ioクラス
実行結果を

# ファイルdataの内容はabcdefg

File.open("data") do |io|
  while not io.eof?
    print io.read(1)
    io.seek(0,IO::SEEK_SET)
  end
end

#答え: aが表示され続ける

CPUが6割、メモリ6GB食われてた。

EOFとは

End of Fileの略
##ioクラスメソッド、SEEK_SET

instance method IO#seek

ファイルポインタを whence の位置から offset だけ移動させます。 offset 位置への移動が成功すれば 0 を返します

ファイル上の文字にポインタなる住所のようで住所じゃないものがある。らしい
今回は、io.seek(0,IO::SEEK_SET)でオフセットを0に指定しているため、
文字の読み込みが最初のaからすすまない(ずっとaが読み込まれる)らしい

strgtime

実行結果にあう、選択肢を選べ

# 問題
t = Time.gm(1970,1,1)
puts t.strftime("#ここに代入する式を選択")
# => 1970/01/01

#選択肢
1, %y/%m/%d   ,2, %Y/%M/%d
3, %y/%M/%d      ,4, %Y/%m/%d

#答え:4

strgtimeメソッド

instance method Time#strftime

strgtimeで代表的なもの

1 2 3 4 5 6 7
4桁の西暦 2桁の西暦 時刻
%Y %y %m %d %H %M %S

Rubyの予約語

予約語を選べ

# 問題
while   rand
goto   class   const

#答え whileとclass

予約語: 既にruby側で定義されている言葉。自分で使おうとしても使えない。

to_s

実行結果をかけ

# 問題
x = 0
[1,2,3].each do |x|
 print x.to_s + " "
end
puts x

#解答 1  2  3  0
# 1,2,3は表示上は数字型だか、実は文字型

to_s :整数型データを文字型に変換する

検証コード

x = 0
[1,2,3].each do |x|
  print x.to_s + " "
  print x.to_s.class
end
puts x

# =>
# x = 0

[1,2,3].each do |x|
  print x.to_s + " "
  print x.to_s.class
  o_s.class
end
puts x

# 0
# => nil

Rubyの偽の値

#問題
nil  0   ""
false  0.0   NULL

#解答  nil と  false

例外処理: 適切な選択肢を

# 問題
y = false
y ##AAA## (raise "failed")
puts("succeeded!")
#選択肢
1, |  ,2, ||   ,3, &    ,4, &&

#答え   &&

&&演算子

&&演算子は左辺の評価結果がfalseの場合は、右辺を評価せずに次の処理に進む
|| 演算子は、左辺の評価結果がtrue の場合は、右辺を評価せずに次の処理に進む
|演算子と&演算子は、左辺の評価結果に関係なく、右辺を評価する

raise 例外

raiseは例外を投げるので、それ以降の処理を飛ばす
それを捕捉したい場合は、begin rescue endを使う

今回の場合、raiseが実行されるとputs("succeeded!")が実行されないのを、考慮

範囲オブジェクト

1から10まで表示sるコードを選べ

  1. (1.10).each do |i| puts i end
  2. (1..10).each do |i| puts i end
  3. (1...10).each do |i| puts i end
  4. (1....10).each do |i| puts i end

ans => 2

範囲オブジェクト

定義されているのは、点2つと点3つ。
2つは2から10以下、3つは2から10未満

gsub!

実行するとどうなる

# 問題
HOGE = "hoge"
HOGE.gsub!("hoge", "piyo")
print HOGE

# 答え  警告は発生せず、「piyo」が表示される。

gsub! :破壊的メソッド

アルファベット大文字で始まる識別子は定数は定数なので、新たに代入を行う際には警告が発生します。
しかし、gsub!は破壊的メソッドを呼び出しているだけなので、警告は発生せず、文字列は「piyo」に書き換わります。

例外

正しい記述を選べ

  1. beginによって例外を捕捉する際は、例外の可能性がある処理をbeginからrescueの間に記述する。
  2. ひとつの処理に対して複数のrescueは、指定できない。
  3. 例外オブジェクトのメソッドstacktraceにより、例外スタックを取得できる。
  4. ensureは、必ず記述する必要がある

ans => 1

stacktraceとは

stack trace - 「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

エラーが発生したときに表示される内容で、そのエラーが発生するまでの過程(どんな処理がどの順番で呼び出されたかの流れ)を、ざっくりと表示したもの

エラーコード

以下のコードの ##AAA##ZeroDivisionError が発生した時の処理を記述したい。適切なコードを選択

# 問題
begin
  puts 10 / 0 #ZeroDivisionError
  ##AAA##
  print "ZeroDivisionException:", ex.message
end
  1. rescue ZeroDivisionError = ex
  2. rescue ZeroDivisionError ex
  3. rescue ZeroDivisionError -> ex
  4. rescue ZeroDivisionError => ex

ans => 3

試してみて

begin
  puts "hello"
  puts 10 / 0
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  rescue ZeroDivisionError => ex
    puts "good bye"
    print "ZeroDivisionException:", ex.message
end
begin
  puts "hello"
  puts 10 / 0
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  puts "good afternoon"
  rescue Exception => ex
    puts "good bye1111111"
    print "message:", ex.message
  rescue ZeroDivisionError => ex
    puts "good bye2222222"
    print "ZeroDivisionException:", ex.message
end

参照: Ruby 例外について

?A

コード実行どうなる

# 問題
p ?A

#答え "A"

=>

#コード1 
p "A".ord
# => 65

#コード2
p 65.chr 
#=> "A"

65とは

unicode上のAの番号的な


13日目

クラスの継承

# エラーにならないものを選べ
class Hoge < Object ; end
class Hoge << Object ; end
class Hoge < Kernel ; end
class Hoge << Kernel ; end

# A  1のみ

クラスの継承は<
なお、Kernelはモジュールなので不可

module Kernel

Kernel.call
=>Module

全てのクラスから参照できるメソッドを定義しているモジュール。 Objectクラスはこのモジュールをインクルードしています。Objectクラスのメソッドは実際にはこのモジュールで定義されています。

to_i(n)

to_iメソッドは、文字列をn進数の表現と見なして整数に変換。文字列の先頭から10進数と見なせる部分を切り取って変換し、見なせる部分がなければ0を返す。

p "12abc".to_i =>123
p "abc12".to_i =>0
p "ab12c".to_i =>0
p "1abc2".to_i =>`1

正規表現

s = "a;b:c;d:e;f"
p s.split (/:|;/)
=>["a", "b", "c", "d", "e", "f"]

配列と範囲オブジェクト

a=[1,2,3,4]

a[1,3]    => [2,3,4]
a[1..3]   => [2,3,4]
a[1...3]  => [2,3]
a[1....3] => error
a[2..-1]  => [3,4]

範囲オブジェクトは文字列にも使える

a="abcdefghijk"
a[1,3] = "x"
p a # =>  "axefghijk"
a[1..3] = "x"
p a # =>  "axefghijk"
a[1...3] = "x"
p a # =>  "axdefghijl"

&と&&、|と||

a = [1,2,3,4]
b = [1,3,5,7]

p a & b =>[1, 3]
p a && b =>[1, 3, 5, 7]
p a | b =>[1, 2, 3, 4, 5, 7]
p a || b =>[1, 2, 3, 4]
1 作用
& 日本語の”且つ”と同じ。
&& 左辺が真なら、右辺を評価して、右辺を返す
パイプ1本 日本語の”又は”と同じ
パイプ2本 左辺が真なら、右辺を評価せずに、左辺を返す

※パイプ=『|』。エスケープできなかった

可変長引数

def sum (##AAA##)
  total = 0
  a.each {|i| total += i }
  return total
end
puts sum(1, 2, 3, 4, 5)
=>15

delete_if = reject! 破壊的メソッド

ブロックの戻り値が真になった要素を削除。なお、rejectは非破壊的

a= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a.delete_if{|v| v % 2 == 0 }
=>[1, 3, 5, 7, 9]
p a => [1, 3, 5, 7, 9]

enum.each_with_index {|item, idx| block }

繰り返しごとにブロック引数itemには各要素が入り、idxには0,1,2と番号が入る

a = ["apple", "orange", "grape", "pine"]
a.each_with_index{ |item, i| print i, ":", item, "\n" }
=> 
0:apple
1:orange
2:grape
3:pine

array.each_index {|index| block }

『ほぼ』each_with_indexと同じ。繰り返しごとにブロック引数には各要素のインデックス(位置)の整数が入ります。戻り値はレシーバ自身

hash.each_pair {|key, val| block }

eachと同じ

hash.each_key {|key| block }

繰り返しごとにブロック引数keyにはキーが入る。

hash.each_value {|val| block }

繰り返しごとにブロック引数valにはキーの値が入る。each_何たらが他にも結構あるので、見ておこう

shift とunshift 破壊的メソッド

shiftメソッドは、配列の最初の要素を削除し、その要素を返します。レシーバ自身を変更するメソッドです。配列が空のときはnilを返します。

s = ["one","two","three"]

s.shift         => "one" ※先頭のoneを削除
s.shift         => "two" ※先頭のtwoを削除
s.unshift       => ["three"] ※引数が無いので、何もしてない
s.push "four"   => ["three", "four"]
p s             =>["three", "four"]

compactとuniq

a = [:a,:a,:b,:c]
a[5] = :e
a.concat([:a,:b,:c])
a.compact
a.uniq
p a
=> [:a, :a, :b, :c, nil, :e, :a, :b, :c]

concat, compact, uniqのうち、破壊的メソッドはconcatのみなので、結果、元の配列aに影響を及ぼすのはconcatのみ

concat 破壊的 = push = <<

配列の末尾に引数を結合。感嘆符が無い破壊的メソッド

conpact 非破壊的

配列からnilを取り除いた、新しい配列を作成感嘆符がついたconpact!が破壊的。

uniq 非破壊的

配列から重複した要素を取り除いて、新しい配列を作成感嘆符が付くと破壊的に。

arr = [1, 2, 5, 5, 1, 3, 1, 2, 4, 3]
p arr.uniq
[1, 2, 5, 3, 4]

map = collect

a = [1, 2, 3, 4, 5, 6]

a.collect {|v| v * 2}
=> [2, 4, 6, 8, 10, 12]
a.inject {|v| v * 2}
=> 32
a.each {|v| v * 2}
=> [1, 2, 3, 4, 5, 6]
a.map {|v| v * 2}
=>[2, 4, 6, 8, 10, 12]
a.select {|v| v * 2}
=> [1, 2, 3, 4, 5, 6]
a.execute {|v| v * 2}
=> error  undefined method

どうしたらinjectが32になるか、リファレンス見ても理解できない

%w記法

配列を作る

sarray = %w(Apple Orange Grape)
sarray.each {|v| print v, " "}
#
Apple Orange Grape

zip

実行結果になるように、##AAA##に記述するコードを選んで下さい

a = ["a", "b", "c"]
b = [1, 2, 3]
##AAA##

#実行結果
["a", 1]
["b", 2]
["c", 3]

#選択肢
a.zip(b).each{|x| p x }
a.zip(b){|x| p x }
[a, b].zip{|x, y| p [x, y] }
[a, b].transpose.each{|x, y| p [x, y] }

#答え 1,2,4

zip

行と列を入れ替える。足りない要素はnilを返す

transpose

zipと同様、行と列を入れ替える。要素が足りない場合、例外IndexErrorを発生。

EOB

以下のコードは正しく動きません。修正案を。

s = <<EOB
Hello, Ruby World.
Hi, Ruby World.
Goodbye, Ruby World.
  EOB

#解答
5行目のEOBの前の空白を削除する。

encoding

puts "hello".encoding.name
UTF-8
=> nil

chop 非破壊的

文字列の末尾から1文字を取り除いた新しい文字列を返す。!が付くと、破壊的

chomp 非破壊的

文字列の末尾の改行文字を取り除いた新しい文字列を返す。!が付くと、破壊的

^ キャレット

名をキャレット、否定をする

puts "0123456789-".delete("^13-56-")
=> 13456-

13456-に該当『しない』ものを削除している

正規表現

p "abc def 123 ghi 456".scan(/\d+/).length
=> 2

\dは10進数なので、10進数から始まる部分を配列で返し(scan)、その要素の数lengthを返してる

scan(string)

指定した正規表現のパターンとマッチする部分を文字列からすべて取り出し、配列にして返す。

p "HogeHOGEhoge"[/[A-Z][^A-Z]+/]
=> "Hoge"

大文字と小文字のアルファベットで構成される文字列を返している

invert(hash)

hashのキーと値を入れ替える

h = {1 => "Hoge", 2=> "Piyo", 3=>"fuga"}
p h.invert
#
{“Hoge”=>1, “Piyo”=>2,“fuga”=>3 }

update と sort

a = {"Foo" => "Hoge", "Bar" => "Piyo", "Baz" => "Fuga"}
b = {"Foo" => "hoge", "Bar" => "piyo", "Baz" => "fuga"}
p a.update(b).sort{ |a, b| a[1] <=> b[1] }

[["Baz", "fuga"], ["Foo", "hoge"], ["Bar", "piyo"]]

update

わかりづらい

sort

配列の要素をソートした新しい配列を返します。「要素1 <=> 要素2」の結果が-1なら要素1が先、0なら同じ、1なら要素2が先となります。

ルート

以下のコードは、ファイル test . txt を読み、文字を逆順に書き込む処理です。「##AAA##」に入る適切な記述を選びなさい。

open("test.txt","##AAA##") do |f|
  data = f.read.chomp
  data.reverse!
  f.rewind
  f.write data
end
#選択肢
a  w  r  a+  r+  w+

組み込み関数openの第2引数には、ファイルのオープン モードを指定します。

  • r、w、a に + を付けると、読み書き 両用でオープンします。
  • w+ を指定すると元ファイルの内 容を空にします。
  • a+ を指定すると、追記モードとなり、 元のファイルを書き換えることができません。

chr と ord は対義語的

puts 65.chr   => "A"
puts "a".ord  => 97

コードポイントの話。n.chrは,nで登録されている文字を返す。string.ordはstringのコードポイントを返す。メソッドの意味は覚えてるけど、もう『65を見たらA』と覚えるしか。

securerandom Module

安全な乱数発生器のためのインターフェースを提供するモジュール

require 'securerandom'
SecureRandom.urlsafe_base64

urlsafe_base64

ランダムで URL-safe な base64 文字列を生成して返します。