1. ホーム
  2. ruby

[解決済み] Ruby - 変数が配列でない場合、エレガントに配列に変換する。

2022-06-18 09:49:05

質問

配列、単一要素、またはnilが与えられた場合、配列を取得します - 後者2つはそれぞれ単一要素の配列と空の配列です。

Rubyはこのように動くと勘違いしていました。

[1,2,3].to_a  #= [1,2,3]     # Already an array, so no change
1.to_a        #= [1]         # Creates an array and adds element
nil.to_a      #= []          # Creates empty array

しかし、本当に得られるのは

[1,2,3].to_a  #= [1,2,3]         # Hooray
1.to_a        #= NoMethodError   # Do not want
nil.to_a      #= []              # Hooray

ですから、これを解決するには、別の方法を使うか、あるいは、使用する予定のすべてのクラスのto_aメソッドを修正してメタプログラミングする必要があります - これは私にとってオプションではありません。

というわけで、メソッドです。

result = nums.class == "Array".constantize ? nums : (nums.class == "NilClass".constantize ? [] : ([]<<nums))

という問題があります。エレガントな方法はないでしょうか?(これがRuby的な解決方法だとしたら驚きです)


これはどのような用途があるのでしょうか?なぜ配列に変換するのでしょうか?

RailsのActiveRecordで、呼び出すと。 user.posts を呼び出すと、投稿の配列、単一の投稿、またはnilのいずれかが返されます。この結果に対して動作するメソッドを書く場合、そのメソッドが0個、1個、または多数の要素を持つ配列を受け取ることを想定するのが最も簡単です。メソッドの例です。

current_user.posts.inject(true) {|result, element| result and (element.some_boolean_condition)}

どのように解決するのですか?

[*foo] または Array(foo) はほとんどの場合うまくいきますが、ハッシュのようないくつかのケースでは台無しになります。

Array([1, 2, 3])    # => [1, 2, 3]
Array(1)            # => [1]
Array(nil)          # => []
Array({a: 1, b: 2}) # => [[:a, 1], [:b, 2]]

[*[1, 2, 3]]    # => [1, 2, 3]
[*1]            # => [1]
[*nil]          # => []
[*{a: 1, b: 2}] # => [[:a, 1], [:b, 2]]

ハッシュでも機能する方法は、メソッドを定義することくらいしか思いつきません。

class Object; def ensure_array; [self] end end
class Array; def ensure_array; to_a end end
class NilClass; def ensure_array; to_a end end

[1, 2, 3].ensure_array    # => [1, 2, 3]
1.ensure_array            # => [1]
nil.ensure_array          # => []
{a: 1, b: 2}.ensure_array # => [{a: 1, b: 2}]