Ruby silver模擬試験誤答一覧 その3
Hashでblockを使うと
ブロック内部では各要素が配列(1つ目にキー、2つ目に値)の形で渡される。
irb(main):005:0> h.each {|p| p p } [:a, 100] [:b, 200] => {:a=>100, :b=>200}
Integer#step
では、ループの中で自分自身を含む。
(例:1.step(5,1)
という使われ方をしていたら、最初のブロックの|i|は1
である。つまりi
が「1,2,3,4,5」とインクリメントするよう5回のループが発生する。)
step
という言葉から、最初のループから一回インクリメントされた値がブロックに渡されそうだが、実際はそんなことはない。
条件式としての範囲式
一体どこで活用するのかよくわからないが、不思議な評価の仕方をする範囲式。
素敵な解説記事があった。
問題はこのようなもの
10.times{|d| print d == 3..d == 5 ? "T" : "F" }
範囲式とは完全に別物と考えること!範囲の概念はここでは用いない。
まず最初に左側の条件式(式1とする)が真になるまで、この条件式はfalseを返し続ける。今回の場合「d = 0,1,2」までがfalseとなる。
「d = 3」で式1がtrueになると、今度は右側の条件式(式2とする)が真となるまで「true」を返し続ける。今回の場合「d = 3,4」まではtrueを返す。
「d =5」で式2がtrueになると、式全体としてはtrue
を返す。ただし、式1も式2も今までの値をリセットする。
「d = 6、7、8、9」で式1はfalseを返し続ける。
追記)Feature #5400: Remove flip-flops in 2.0 - Ruby master - Ruby Issue Tracking System
なにぃ・・・
Hash#invertでキーが重複した場合。
後ろに出てきた要素のinvertが返るよ。
irb(main):019:0> p ({prefecture: "KANAGAWA", "address": "KANAGAWA"}).invert {"KANAGAWA"=>:address} => {"KANAGAWA"=>:address}
putsの引数にしてエラーが出るのはどれか
超頻出と思われる。
- "10".oct
oct
メソッドは原則8進数への変換を行うが、接頭辞に応じてn進数への変換を行える。
irb(main):026:0> puts "0x1a3".oct 419 irb(main):027:0> puts "0b0010".oct 2 irb(main):030:0> puts "0o10".oct 8
これと対照的なのがhex
で、こちらは接頭辞を無視して、16進数に直す。16進数と認められない文字があればそれ以降は無視する。
* 080
接頭辞の0自体が「8進数」を示すものであるので、そのあとに「8」が続いてしまうので×。
irb(main):032:0> puts 070 56 => nil
- "110".to_i(2)
to_s
に引数を渡すと、n進数と解釈して、その10進数表記を返してくれる。
irb(main):036:0> "0xccc".to_i(16) => 3276
Aray#transpose
trasposeメソッドは2つの配列が入った配列の行と列の入れ替えを行うメソッド。
irb(main):037:0> a = ["a","b","c"] => ["a", "b", "c"] irb(main):038:0> b = [1,2,3] => [1, 2, 3] irb(main):040:0> [a,b].transpose => [["a", 1], ["b", 2], ["c", 3]]
この2つの配列を入れ子配列ではなく、普通の()にしてメソッドを実行する問題があるが、これは動作しないので間違い。
irb(main):016:0> (a,b).transpose.each do |i| irb(main):017:1* p i irb(main):018:1> end SyntaxError: (irb):16: syntax error, unexpected '.', expecting '=' (a,b).transpose.each do |i| ^ from /home/pyons/.rbenv/versions/2.1.0/bin/irb:11:in `<main>'
String#indexの第2引数
に指定するのは「探索開始位置」。
String#deleteの挙動
instance method String#delete (Ruby 2.6.0)
問題はこちら
puts "0123456789-".delete("^13-56-")
^
が接頭辞としてついている文字列は削除しない。(それ以外をすべて削除している)^
がついているものに関しては、直後の「文字」だけでなく、「文字列」が対象となる点に注意したい。
これは範囲をとっている文字にも言えることで、
irb(main):001:0> "ABCDEFG".delete("A-Z") => "" irb(main):002:0> "ABCDEFG".delete("^A-Z") => "ABCDEFG"
下の例では、^をA-Zに指定したため、文字列は一文字も削除されることなく残っている。 実際の問題文では
puts "0123456789-".delete("^13-56-")
という式が出ていた。1と3456とハイフンだけは生き残り、それ以外がすべて削除される。
また、範囲指定は「文字列の両端にない場合だけ」である。更にdeleteメソッドは帰り値が「削除が完了した文字列」ではなく、「削除した文字列」である点に注意する必要がある。
これは誤り。String#delete
の戻り値「削除が完了した文字列」。削除を行った文字列を戻り値とするメソッドはArray#delete
とかArray#delete_at
とかHash#delete
など。
Ruby2.2以前のHash宣言
Ruby2.2より前だと、「キーと値のペアを:
を使って書くときに限り」キーに文字列を指定することが出来なかったようだ。
pyons@LAPTOP-SF87NLCB:~$ ruby -v ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux] pyons@LAPTOP-SF87NLCB:~$ irb irb(main):001:0> a = {"a" => "b"} => {"a"=>"b"} irb(main):002:0> a = {"a":"b"} SyntaxError: (irb):2: syntax error, unexpected ':', expecting => a = {"a":"b"} ^ (irb):2: syntax error, unexpected '}', expecting end-of-input from /home/pyons/.rbenv/versions/2.1.0/bin/irb:11:in `<main>'
もちろんこれより新しいRubyではこの書き方はサポートされている。
pyons@LAPTOP-SF87NLCB:~$ ruby -v ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux] pyons@LAPTOP-SF87NLCB:~$ irb irb(main):001:0> a = {"a":"b","c":"d"} => {:a=>"b", :c=>"d"}
Dir#extname
は実装されていない。Fileクラスの実装である。Dir#open
はディレクトリを開くメソッドとして実装されている。
引数に「*」記号
配列のオブジェクトを返してくれるらしい。 可変長引数としてはやったけど、メソッドに引数を送っているわけではなく、代入を行っているだけなので、このような使い方があるのを知らなかった。
irb(main):001:0> a = *"b" => ["b"] irb(main):002:0> p a ["b"] => ["b"] irb(main):003:0> a = *"b","c","d" => ["b", "c", "d"] irb(main):004:0> p a ["b", "c", "d"] => ["b", "c", "d"]
また、引数としてメソッドで渡す場合、配列に変換が行われた後で、配列そのものとして渡されるのではなく、配列の要素一つ一つが順番に渡される。
Hashは配列のネストの形にto_a
を用いて変更することが出来る。
hash = {a: 100, b: 200} def splat_hash(a, b) p a p b end splat_hash(*hash)
この問題では、メソッド呼び出しの時に、ハッシュがto_a
で配列化され、[[:a, 100], [:b, 200]]
となった後で、各要素([:a, 100]と[:b, 200])が、それぞれ仮引数aとbに代入されている。
String#index
indexメソッドは2つ目の引数に数字をとると、検索をその文字列から始めるが、検索開始時点を0にリセットしているわけではない。あくまで、戻り値はインデックスとしての絶対値である。
IO#seek
seekメソッドの引数には必ず2つの引数を指定する。教科書には「一番目の引数で指定した数だけ、2番目の引数の場所から移動する。」と書いてある。ただし、指定しなければ、先頭を表す「SEEK_SET」が割り当てられる。
定数 | 意味 |
---|---|
SEEK_SET | ファイルの先頭 |
SEEK_CUR | 現在のポインタの位置 |
SEEK_END | ファイルの末端 |
複数の例外クラスを一つのrescue節で捕捉する
には、先ほどやったように、「配列の要素一つ一つを引数として渡す」ことのできるsplat演算子を利用して、rescue節に記述する。
begin putss "HelloWorld" rescue *[StandardError, SyntaxError, ArgumentError] puts "Rescued!" end
pyons@LAPTOP-SF87NLCB:/mnt/c/Users/broad/OneDrive/products/Ruby技術者認定試験$ ruby 5-1-1.rb Rescued!
Dateクラス
Dateクラスは組み込みクラスでない、添付ライブラリのはずなので出題範囲でないというのが一応の建前だが、Rexでよく出題されてしまうので、一応抑えておく。
require "date" d = Date.new(2015,1,5) puts d.strftime("%F") #=>2015-01-05
require "date" d = Date.new(2015,1,5) puts d.strftime("%Y-%m-%d")
require "date" d = Date.new(2015,1,5) puts d.strftime("%x") #=> 01/05/15 t = Time.new(2015,1,5) puts t.strftime("%x") #=> 01/05/15
String#splitの挙動
irb(main):002:0> "a b c d".split() => ["a", "b", "c", "d"] irb(main):003:0> "a\nb\nc\nd".split() => ["a", "b", "c", "d"] irb(main):004:0> "a\nb\nc\nd".split(//) => ["a", "\n", "b", "\n", "c", "\n", "d"] irb(main):006:0> "a\tb\tc\td".split(//) => ["a", "\t", "b", "\t", "c", "\t", "d"] irb(main):007:0> "a b c d".split(//) => ["a", " ", "b", " ", "c", " ", "d"]
splitの引数に何も指定しなければ「空白」や「空白文字」も切り分けの対象に含まれる。
一方、splitの引数に//
を指定すると、「すべての文字が一つの要素を構成する配列」に変換される。
この「すべての文字」とは空白文字や空白を含む。