Ruby on Rails 3.0.10を使用しており、条件付きの方法でハッシュキーと値のペアを作成したいと考えています。つまり、条件が一致した場合にキーとそれに関連する値を追加するには:
hash = {
:key1 => value1,
:key2 => value2, # This key2\value2 pair should be added only 'if condition' is 'true'
:key3 => value3,
...
}
どうすればコードを"good" readabilityに保つことができますか? merge
メソッドを使用するように「強制」されていますか?
私はtap
を好みます。これは、要素のハッキーな削除を必要とせず、ハッシュが構築されるスコープを明確に定義することにより、ここで説明したものよりもクリーンなソリューションを提供すると思います。
また、不要なローカル変数を宣言する必要がないことも意味します。
これまでに遭遇したことがない場合でも、tap
は非常にシンプルです。これは、ブロックを受け入れ、呼び出されたオブジェクトを常に返すObject
のメソッドです。したがって、条件付きでハッシュを構築するには、次のようにします。
Hash.new.tap do |my_hash|
my_hash[:x] = 1 if condition_1
my_hash[:y] = 2 if condition_2
...
end
tap
には多くの興味深い用途がありますが、これは1つにすぎません。
機能的アプローチ:
hash = {
:key1 => 1,
:key2 => (2 if condition),
:key3 => 3,
}.compact
Ruby> = 2.4.0またはactive-supportのどちらも使用していない場合は、.compact
沿って .reject { |k, v| v.nil? }
。
読みやすさが気になる場合は、シンプルに保つのがおそらく最善です。
hash = {}
hash[:key1] = value1
hash[:key2] = value2 if condition?
hash[:key3] = value3
...
複雑にしないでおく:
hash = {
key1: value1,
key3: value3,
}
hash[:key2] = value2 if condition
このようにして、特別なケースを視覚的に分離することもできます。ハッシュリテラルの割り当てに埋もれてしまうと、気づかれない可能性があります。
そのような状況では、merge
と三項演算子を使用します。
hash = {
:key1 => value1,
:key3 => value3,
...
}.merge(condition ? {:key2 => value2} : {})
最初にこうしてハッシュを構築します:
hash = {
:key1 => value1,
:key2 => condition ? value2 : :delete_me,
:key3 => value3
}
次に、ハッシュを構築した後にこれを実行します。
hash.delete_if {|_, v| v == :delete_me}
ハッシュが凍結されているか、または不変でない限り、これは事実上、存在する値のみを保持します。
ある種の列挙可能なデータからハッシュを構築する場合、インジェクトを使用できます。次に例を示します。
raw_data.inject({}){ |a,e| a[e.name] = e.value if expr; a }
このように単純:
hash = {
:key1 => value1,
**(condition ? {key2: value2} : {})
}
それが役に立てば幸い!
オプションの属性から別の場所にハッシュを入力する場合は、フェッチを使用すると便利です。この例を見てください:
def create_watchable_data(attrs = {})
return WatchableData.new({
id: attrs.fetch(:id, '/catalog/titles/breaking_bad_2_737'),
titles: attrs.fetch(:titles, ['737']),
url: attrs.fetch(:url, 'http://www.netflix.com/shows/breaking_bad/3423432'),
year: attrs.fetch(:year, '1993'),
watchable_type: attrs.fetch(:watchable_type, 'Show'),
season_title: attrs.fetch(:season_title, 'Season 2'),
show_title: attrs.fetch(:id, 'Breaking Bad')
})
end