😎

Ruby で任意の要素を配列なら配列のまま、それ以外なら配列に変換する

2024/09/23に公開

何かしらの値を配列として扱いたい場合、通常は [] で囲むことが多いと思います。

[a]

このときに a が配列だった場合、単純に [] で囲むとネストした配列になります。

a = [1, 2, 3]
[a]   # => [[1, 2, 3]]

こういう場合に『配列だった場合は配列のまま』になってほしいことが稀によくあります。

Kernel.#Array メソッドを利用する

こういうときに Kernel.#Array を利用することで『配列は配列のまま、それ以外は配列に変換する』ということが実現することができます。

a = 42

# これは配列になる
p Array(a)   # => [42]


b = [1, 2, 3]

# これは配列のまま
p Array(b)   # => [1, 2, 3]

内部で呼び出されるメソッド

Array(a) という呼び出しがあった場合は内部で次のような優先順位で処理されます。

  1. a.to_ary が呼び出さればその結果を返す
  2. 次に a.to_a が呼び出さればその結果を返す
  3. それでもなければ [a] を返す
class Array1
  def to_a
    ["Array1"]
  end
end

class Array2 < Array1
  def to_ary
    ["Array2"]
  end
end

# Array1#to_a が呼び出される
p Array(Array1.new)
# => ["Array1"]

# Array2#to_a ではなくて Array2#to_ary が優先して呼び出される
p Array(Array2.new)
# => ["Array2"]

また #to_ary#to_a が配列でない場合は例外が発生します。

class Array1
  def to_a
    ["Array1"]
  end
end

class Array2 < Array1
  def to_ary
    ["Array2"]
  end
end

# Array1#to_a が呼び出される
p Array(Array1.new)
# => ["Array1"]

# Array2#to_a ではなくて Array2#to_ary が優先して呼び出される
p Array(Array2.new)
# => ["Array2"]

注意: nil を渡すとどうなる?

Array(nil) を渡した場合 [] が返ってきます。

p Array(nil)   # => []

これは nil.to_a[] を返すからになります。

# nil.to_a は [] を返す
p nil.to_a   # => []

仮に [nil] を返してもらいたい場合は工夫する必要がありますねー。

注意: Hash オブジェクトを渡すとどうなる?

もう1個ぎょっとなる挙動なんですが Array(a: 1, b: 2)[[:a, 1], [:b, 2]] になります。

p Array(a: 1, b: 2)
# => [[:a, 1], [:b, 2]]

これは Array(a: 1, b: 2)Array({ a: 1, b: 2 }) みたいに Hash オブジェクトを渡したことになるんですが、これも Hash#to_a が内部で呼び出されているからになります。

data = { a: 1, b: 2 }
p data.to_a
# => [[:a, 1], [:b, 2]]

# これも内部で data.to_a が呼び出される
p Array(data)
# => [[:a, 1], [:b, 2]]

これも Hash のまま配列にするには工夫する必要がありますねー。

GitHubで編集を提案

Discussion