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"]
誰でも考えそうだから既出のアイディアだったらゴメンね。
って、もっと高度なことをまめさんがしてました^ ^;
まあ折角書いたから..
ゴメンナサイm(__)m
関連記事:RubyのSymbol#to_procを考えた人になってみる
(追記:2012-2-14)Twitterを通してすごい荒業を知ったよ2
[1,2,3].map(&1.method(:+)) #=> [2,3,4]
スゴイね!でもメソッド呼び出しのオブジェクトが引数と入れ替わっちゃってるから、:+, :*くらいしか用途がなさそうだけどね..
blog comments powered by Disqus