Help us understand the problem. What is going on with this article?

Rails の便利なメソッド(Array 編)

More than 3 years have passed since last update.

この前、数値オブジェクトの拡張メソッドをまとめたので、次は Array の Rails 便利メソッドをまとめました。

可読性を向上させる

from(position), to(position)

位置を指定して値を取り出せる。from は引数の位置「から」、to は引数の位置「まで」。

[0, 1, 2, 3].from(1) #=> [1, 2, 3]
[0, 1, 2, 3].to(2) #=> [0, 1, 2]

from と同じことをしようとすると

[0, 1, 2, 3][1..-1] #=> [1, 2, 3]
[0, 1, 2, 3][1, 3] #=> [1, 2, 3]

という感じになるので、とても直観的。

second, third, fourth, fifth, forty_two

パッと見の通り、その位置の値を返す。Ruby に first があるので、その続きですね。

[1, 2, 3].second #=> 2
[1, 2, 3].third #=> 3
(1..42).to_a.forty_two #=> 42

append, prepend

append<< のエイリアス、prependunshift のエイリアス。
ただのエイリアスだけど、これも直観的なので、個人的にはよく使います。

[0, 1, 2].append(3) #=> [0, 1, 2, 3]
[0, 1, 2].prepend(-1) #=> [-1, 0, 1, 2]

グループ分けする

in_groups_of(number, fill_with = nil)

与えた number の長さの配列にグループ化する。
「10 人を 3 人ずつの班に分ける」というような使い方ができる。

(1..10).to_a.in_groups_of(3) #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, nil, nil]]

デフォルトでは、要素数が number に足りない場合は nil が追加されるが、引数で指定する事も出来る。

(1..10).to_a.in_groups_of(3, 'hoge') #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, "hoge", "hoge"]]

# false を渡すと補完しなくなる
(1..10).to_a.in_groups_of(3, false) #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

さらにブロックで処理も与えられる。

('A'..'J').to_a.in_groups_of(3, false) {|g| puts "#{g.first}班 : #{g}" }
# A班 : ["A", "B", "C"]
# D班 : ["D", "E", "F"]
# G班 : ["G", "H", "I"]
# J班 : ["J"]

in_groups(number, fill_with = nil)

与えた number の数にグループ化する。
「10 人を 3 つの班に分ける」というような使い方ができる。

(1..10).to_a.in_groups(3) #=> [[1, 2, 3, 4], [5, 6, 7, nil], [8, 9, 10, nil]]
(1..10).to_a.in_groups(2) #=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]

この時、足りない要素数は 1 以内になるように分けてくれる。
また、同じように補完する値を指定可能。

(1..10).to_a.in_groups(3, 'hoge') #=> [[1, 2, 3, 4], [5, 6, 7, "hoge"], [8, 9, 10, "hoge"]]
(1..10).to_a.in_groups(3, false) #=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]

ブロックも

('A'..'J').to_a.in_groups(3, false) {|e| puts "#{e.first}班 : #{e}" }
# A班 : ["A", "B", "C", "D"]
# E班 : ["E", "F", "G"]
# H班 : ["H", "I", "J"]

split(value = nil)

指定した値にマッチ or ブロックの結果が true になるところで配列を分割する。

(1..5).to_a.split(3) #=> [[1, 2], [4, 5]]
[1, 2, 'a', 4, 5].split {|a| a.kind_of?(String) } #=> [[1, 2], [4, 5]]

文字列に変換する

to_sentence(options = {})

要素を連結して、文字列に変換する。
その際、以下のオプションが指定できる

オプション 説明
words_connector 要素を連結する際の文字列
two_words_connector 配列の要素が 2 の場合の連結文字列
last_word_connector 最後の要素を連結する際の文字列
locale I18n 対応、言語を指定出来る
['A', 'B', 'C'].to_sentence #=> "A, B, and C"

# 言語の指定
['A', 'B', 'C'].to_sentence(locale: :ja) #=> "AとBとC"

# 連結する文字列の指定
['A', 'B', 'C'].to_sentence(words_connector: ' と ') #=> "A と B, and C"
['A', 'B', 'C'].to_sentence(words_connector: ' と ', last_word_connector: ' そして ') #=> "A と B そして C"

# 要素が 2 つの場合は two_words_connector を使う
['A', 'B'].to_sentence(words_connector: ' と ', last_word_connector: ' そして ') #=> "A and B"
['A', 'B'].to_sentence(two_words_connector: ' あと ') #=> "A あと B"

全部のオプションを指定してみる

locales/ja.yml
ja:
  support:
    array:
      words_connector: '  '
      two_words_connector: ' そして '
      last_word_connector: ' 最後に '
('A'..'J').to_a.in_groups(4, false) {|g| puts "#{g.first}班 : #{g.to_sentence(locale: :ja)}" }
# A班 : A と B 最後に C
# D班 : D と E 最後に F
# G班 : G そして H
# I班 : I そして J

無理矢理(・・;

to_s(format = :default)

Numeric クラスで拡張されている事を紹介しましたが、Array クラスでも拡張されています。
ただ、format が :db しかないのと、id 属性があるオブジェクトの配列にしか使えないのが残念。

User.all.to_a.to_s(:db) #=> "1,2,3,4,5,6,7,8"

このように id を , 区切りで連結して返します。

to_param, to_query, to_xml(options = {})

左から URL のパス、クエリ、XML に変換した文字列を返す。

紹介しておいて何ですが、あんまり使い方が思いつかなかった。。。
まあ、ActionPack の Renderers とか Redirect で使われるているので、どちらかというと Rails 内で使うために用意されているのかな。ただ、ちょっとしたスクリプト書くときに便利かも。

%w(qiita.com pekepek items).to_param #=> "qiita.com/pekepek/items"
%w(Rails coding).to_query('hobbies') #=> "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"

puts [{foo: 1, bar: 2}, {baz: 'hogehoge'}].to_xml
# <?xml version="1.0" encoding="UTF-8"?>
# <objects type="array">
#   <object>
#     <foo type="integer">1</foo>
#     <bar type="integer">2</bar>
#   </object>
#   <object>
#     <baz>hogehoge</baz>
#   </object>
# </objects>

その他

self.wrap(object)

Kernel#Array 基本動作は同じだが、Range や Hash を引数にした場合に挙動が異なる。

# 引数が Array の場合
Array([1, 2, 3]) #=> [1, 2, 3]
Array.wrap([1, 2, 3]) #=> [1, 2, 3]

# Hash の場合
Array(a: 1, b: 2, c: 3) #=> [[:a, 1], [:b, 2], [:c, 3]]
Array.wrap(a: 1, b: 2, c: 3) #=> [{:a=>1, :b=>2, :c=>3}]

# Range の場合
Array(1..3) #=> [1, 2, 3]
Array.wrap(1..3) #=> [1..3]

ちゃんと配列にラップしてくれるメソッドという感じですね。

Rails 5 で追加されるメソッド

最後に Rails 5 で追加されるメソッドも紹介。

second_to_last, third_to_last

last の続きが追加された...!!

[1, 2, 3].third_to_last #=> 1
[1, 2, 3].second_to_last #=> 2

without(*elements)

elements で指定した要素を除いた配列を返す。中身は Array#- してるだけ。

[1, 2, 3].without(1, 2) #=> [3]

inquiry

元々 String#inquiry はあったが、Array にも追加された。
hogehoge? というメソッドが呼べるようになり、実際にメソッド名と同じ要素が合ったら true を返す。

users = %w(pekepek pokopok).inquiry #=> ["pekepek", "pokopok"]
users.pekepek? #=> true
users.pokopok? #=> true
users.tom? #=> false

include?('pekepek') とやっている事は同じですが、引数がないと見た目がすっきりしていいですね。

また、inquiry を呼ぶと、any? がオーバーライドされて、可変長引数を受け取れる様になります。元の any? と同じように引数が一つでもマッチしたら true を返します。

users = %w(pekepek pokopok).inquiry
users.any?('pekepek', 'hogehoge') #=> true
users.any?('hogehoge', 'fugafuga') #=> false

これは結構使いどころ多そうですね。

以上が Array の拡張メソッドです!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away