RubyのEnumerable#mapをもっと便利にしたいよ
次のような名前のリストがあって
langs = ["ruby", "python", "lisp", "haskell"]
名前の先頭を大文字にするとしたら
君ならどうする?
そう普通Enumerable#mapを使って
次のようにするよね
langs = ["ruby", "python", "lisp", "haskell"] langs.map { |lang| lang.capitalize } # => ["Ruby", "Python", "Lisp", "Haskell"]
Enumerable#mapってほんと死ぬほど便利だよ
僕はRubyの魅力の80%は
mapが占めてるんじゃないかって
たまに感じることがあるよ.. :)
でもただ先の例で
大文字にするだけなのにブロックって
ちょっと大げさすぎると思わない?
もちろんそうなんだよ
そう思うRubyistが沢山いたから
mapは次のように書けるようにもなってるんだ
langs = ["ruby", "python", "lisp", "haskell"] langs.map(&:capitalize) # => ["Ruby", "Python", "Lisp", "Haskell"]
シンボルに&を付けてmapに渡すと
暗黙的にSymbol#to_procが呼ばれて
そこで配列の各要素にcapitalizeが適用されるよ
この記法のお陰でmapは一層使い勝手が良くなってるよ
じゃあ今度は先の言語名のリストから
その「言語使いのリスト」に変換してほしいんだけど..
つまり言語名の後に'ist'を付けてほしいんだ*1
そう次のようにするよね
langs = ["ruby", "python", "lisp", "haskell"].map(&:capitalize) langs.map { |lang| lang + 'ist' } # => ["Rubyist", "Pythonist", "Lispist", "Haskellist"]
これって悔しいよね
'ist'を足すだけなのに
またブロックを書かなきゃいけない
同じように次のような場合も
ブロックを書かなきゃいけない
[1, 2, 3].map { |i| i + 10 } # => [11, 12, 13] (1..5).map { |i| i**2 } # => [1, 4, 9, 16, 25] [[1,2,3,4], [5,6,7,8], [9,10,11,12]].map { |arr| arr.last(2) } # => [[3, 4], [7, 8], [11, 12]] ["ruby", "python", "lisp", "haskell"].map { |lang| lang[-2, 2] } # => ["by", "on", "sp", "ll"]
僕はすごく悔しいよ..
そんなわけで..
Enumerable#mappを考えたよ!
module Enumerable def mapp(op=nil, *args, &blk) op ? map { |e| op.intern.to_proc[e, *args]} : map(&blk) end end langs.mapp(:+, 'ist') # => ["Rubyist", "Pythonist", "Lispist", "Haskellist"]
つまりmappでは引数にメソッドと
その引数が取れるんだ
[1, 2, 3].mapp(:+, 10) # => [11, 12, 13] (1..5).mapp(:**, 2) # => [1, 4, 9, 16, 25] [[1,2,3,4], [5,6,7,8], [9,10,11,12]].mapp(:last, 2) # => [[3, 4], [7, 8], [11, 12]] ["ruby", "python", "lisp", "haskell"].mapp(:[], -2, 2) # => ["by", "on", "sp", "ll"]
ブロックを渡せばmapに処理を投げるから
mapの代わりとしても使えるよ
[1, 2, 3].mapp { |i| i + 10 } # => [11, 12, 13] (1..5).mapp { |i| i**2 } # => [1, 4, 9, 16, 25] [[1,2,3,4], [5,6,7,8], [9,10,11,12]].mapp { |arr| arr.last(2) } # => [[3, 4], [7, 8], [11, 12]] ["ruby", "python", "lisp", "haskell"].mapp { |lang| lang[-2, 2] } # => ["by", "on", "sp", "ll"]
誰でも考えそうだから
既出のアイディアだったらゴメンね
って
もっと高度なことをまめさんがしてました^^;
map が面倒なので DelegateMap - まめめも
まあ折角書いたから..
ゴメンナサイm(__)m
関連記事:RubyのSymbol#to_procを考えた人になってみる - hp12c
(追記:2012-2-14)Twitterを通してすごい荒業を知ったよ*2
[1,2,3].map(&1.method(:+)) #=> [2,3,4]
スゴイね!
でもメソッド呼び出しのオブジェクトが
引数と入れ替わっちゃってるから:+, :*くらいしか
用途がなさそうだけどね..