Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[tama.rb#13]Hash#to_procについて

 [tama.rb#13]Hash#to_procについて

Tama.rb #13 チェリー本輪読会にてLTしたスライドになります。
https://tamarb.connpass.com/event/123799/

8aebb410308ec2c655550798e92cd2df?s=128

ken3ypa

March 30, 2019
Tweet

Transcript

  1. Tama.rb#13 ゆるくLT @ken3ypa

  2. Hash#to_procについて Ruby 2.3から導入 to_procはSymbolとかMethodにもある 今までは他には map(&:to_s) とかでおなじみの Symbol#to_proc とか Method#to_proc

    にしかなかったが、Hashにも生えた。 実務で使っている(いた)Ruby1.8.7には…ない… 2
  3. to_procメソッドってなに? https://docs.ruby‑lang.org/ja/latest/method/Hash/i/to_proc.html 3

  4. なるほど … … なるほどな! なるほど!なるほど! なるほどな!!!!!!! 4

  5. (僕は)よくわからないので解説 5

  6. & ← まずこいつ xxx(&b) Proc オブジェクトをブロックとして使う。メソッド呼び出し(super・ブロック付き・yield)/ブ ロック付きメソッド呼び出し を参照。 https://docs.ruby‑lang.org/ja/2.2.0/doc/symref.html#and &を使うとprocオブジェクトをブロック引数の代わりにメソッドに渡せるらしい

    6
  7. & ← まずこいつ https://docs.ruby‑lang.org/ja/2.2.0/doc/spec=2fcall.html#block ブロックの部分だけを先に定義して変数に保存しておき、後からブロック付きメソッドに渡すこ とも出来ます。 それを実現するのが手続きオブジェクト(Proc)です。 それをブロックとして渡 すにはブロック付きメソッドの最後の引数として `&'

    で修飾した手続きオブジェクトを渡 しま す。Proc の代わりにメソッドオブジェクト(Method)を渡す ことも出来ます。この場合、そのメ ソッドを呼ぶ手続きオブジェクトが生成され渡されます。 7
  8. ざっくりまとめると ブロックを受け取れるメソッドが対象(mapとかsumとか) メソッドの最後の引数に&付きで渡す 渡すのは手続きオブジェクト(=つまりProc) 渡すのはProcじゃなくても、 '#to_proc' を持っているオブジェクトならOK つまり:method みたいなSymbol化したオブジェクトやHashでもOK 渡すとProcが返ってくる

    Procにto_procしても自身が返るだけ SymbolクラスやHashクラスのオブジェクトを渡すとProcを返してくれる 8
  9. Hashオブジェクトを&付きで渡してみる h = {1 => 10, 2 => 20, 3

    => 30} def fuga(h) hash end def hoge(&hash) hash end p fuga(h) #=>{1=>10, 2=>20, 3=>30} p hoge(&h) #=>#<Proc:0x0000556990170f08> # やってることは p h.to_proc 変数に格納したHashを&付きで渡してあげると Procオブジェクトが返ってきている 9
  10. 最初のサンプルコードを確認すると h = {1 => 10, 2 => 20, 3

    => 30} [1, 2, 3].map(&h) # => [10, 20, 30] L1: ハッシュを変数に格納する L2: [1, 2, 3]という配列を用意しmap(&h) hにto_procが呼び出され、Procオブジェクトに変換される Procオブジェクトがmapに渡される 配列の各要素([1, 2, 3])が実行時のhの第一引数として渡される 第一引数に渡された各要素がハッシュのキーに一致したらハッシュの値を返す mapメソッドはProcの戻り値を新しい配列に詰め込む [10, 20, 30] Yay!!!! 10
  11. 何が嬉しいの? キーの配列から値をマッピングする際に簡潔にかけるようになる。 h = {1 => 10, 2 => 20,

    3 => 30} p [1, 2, 3].map { |int| h[int] } #[ 10, 20, 30] p [1, 2, 3].map(&h) # [10, 20, 30] 比較するとあら綺麗 11
  12. 便利なのはわかるけど…どこで使うんやお前‥ と思っていたらこんなサイトがあってだな‥ https://exercism.io 12

  13. お題 13

  14. お題 文字列渡して 各アルファベットごとに得点を振ってるから その合計値を返してくれよな!という問題 14

  15. Before class Scrabble SCORE = {1 => %w(A E I

    O U L N R S T), 2 => %w(D G), 3 => %w(B C M P), 4 => %w(F H V W Y), 5 => %w(K), 8 => %w(J X), 10 => %w(Q Z)} def initialize(chars) letters = chars.to_s.upcase.scan(/\w/) @sum = alfabets.inject(0) {|sum, char| sum + aggregate(char)} end def score @sum end def self.score(chars) self.new(chars).score end private def aggregate(char) SCORE.find {|k, v| v.include?(char)}.first end end 15
  16. After class Scrabble SCORE = %w{AEILNORSTU DG BCMP FHVWY K

    JX QZ} .zip([1, 2, 3, 4, 5, 8, 10]) .flat_map {|letters, score| letters.chars.product([score])} .to_h def initialize(chars) letters = chars.to_s.upcase.scan(/\w/) # ["T", "A", "M", "A", "R", "B"] @sum = letters.sum(&SCORE) end def score @sum end def self.score(chars) self.new(chars).score end end p Scrabble.new("tamarb") 16
  17. つまり ロケットハッシュを使わなくてよくなりました!!!!! 17

  18. 18