web-dev-qa-db-ja.com

条件付きの方法でハッシュを構築する

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メソッドを使用するように「強制」されていますか?

40
Backo

私は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つにすぎません。

56
Russell

機能的アプローチ:

hash = {
  :key1 => 1,
  :key2 => (2 if condition),
  :key3 => 3,
}.compact 

Ruby> = 2.4.0またはactive-supportのどちらも使用していない場合は、.compact 沿って .reject { |k, v| v.nil? }

27
tokland

読みやすさが気になる場合は、シンプルに保つのがおそらく最善です。

hash = {}
hash[:key1] = value1
hash[:key2] = value2 if condition?
hash[:key3] = value3
...
10
dwhalen

複雑にしないでおく:

hash = {
  key1: value1,
  key3: value3,
}

hash[:key2] = value2 if condition

このようにして、特別なケースを視覚的に分離することもできます。ハッシュリテラルの割り当てに埋もれてしまうと、気づかれない可能性があります。

5

そのような状況では、mergeと三項演算子を使用します。

hash = {
  :key1 => value1,
  :key3 => value3,
  ...
}.merge(condition ? {:key2 => value2} : {})
3
Dave Morse

最初にこうしてハッシュを構築します:

hash = {
  :key1 => value1,
  :key2 => condition ? value2 : :delete_me,
  :key3 => value3
}

次に、ハッシュを構築した後にこれを実行します。

hash.delete_if {|_, v| v == :delete_me}

ハッシュが凍結されているか、または不変でない限り、これは事実上、存在する値のみを保持します。

2

ある種の列挙可能なデータからハッシュを構築する場合、インジェクトを使用できます。次に例を示します。

raw_data.inject({}){ |a,e| a[e.name] = e.value if expr; a }
1
Dmitry Maksimov

このように単純:

hash = {
  :key1 => value1,
  **(condition ? {key2: value2} : {})
}

それが役に立てば幸い!

1
Dusht

オプションの属性から別の場所にハッシュを入力する場合は、フェッチを使用すると便利です。この例を見てください:

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
0
Excalibur