LoginSignup
44
37

More than 5 years have passed since last update.

そのto_a、必要?

Last updated at Posted at 2014-08-20

割とどうでもいい話。

数字を文字列化した配列が欲しいとき…

number_strings = (1..10).to_a.map{|n| n.to_s }
p number_strings
#=>  ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]


number_strings = []
[*1..10].each{|n| number_strings << n }
p number_strings
#=>  ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

とかやってませんか?

配列を作ってすぐにmapとかeachとかselectするような場合、同じメソッドがRangeにもあるので、to_aは要らない。

ArrayRangeの両方にあるメソッド」は次のような式を実行することで列挙できる。

p ((1..10).to_a.methods & (1..10).methods) - Object.new.methods
#=> [:to_a, :first, :last, :each, :reverse_each, :size, :find_index, :sort, :collect, :map, :select, :reject, :zip, :include?, :count, :cycle, :take, :take_while, :drop, :drop_while, :bsearch, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :lazy]

逆に、Rangeのままでは不都合で、一度Arrayにしなければならないメソッドを調べるには、以下のようにする。

p (1..10).to_a.methods - (1..10).methods
#=> [:to_ary, :[], :[]=, :at, :fetch, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each_index, :length, :empty?, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject!, :transpose, :replace, :clear, :fill, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :shuffle!, :shuffle, :sample, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :pack]

ArrayにあってRangeにない」メソッドは配列を結合するメソッドとか破壊的な変更するメソッドが多いので、比較的どうでもいい。

最初の例はここまで縮められる。

p (1..10).map(&:to_s)
#=> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

こんなこともできる。

p (1..10).select(&:odd?)
#=> [1, 3, 5, 7, 9]

require 'prime'
p (2..100).select(&:prime?)
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

どの例でも返り値はArrayである。

もちろんinjectもある。

p (1..10).inject{|acc, n| acc * n }
#=> 3628800

あとがき

一文につきたかだか5Byteとメソッドコールを一回減らせてもたいしてうれしくないひとが多いらしいので、書くひとがめんどくさくないのならば、結構どうでもいい。僕は1Byteでも減るとうれしい。

追伸

コスト? もちろん余計な変換はしない方が早いし、メモリの使用も少く済むに決まってるじゃないですか。ただし、そこまでけちるようならばそもそもRubyを選択する意義に乏しいので、ユーザーは表面的に見えるコードの簡潔さと、小手先の倹約ではないアルゴリズムそのものに集中するべきである、といふのが私の認識です。といふわけで、(要素数にもよるけど)私はto_aするな! なんて主張をする気は一切ないのです。読みやすいコードが正義。

追伸 2

忘れてたけど[*1..10]みたいに配列リテラルのオペランドにリテラルで作った範囲オブジェクトを展開するのってあまり欲しい機会なくね? ってことを書きたかったんだった。

44
37
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
37