web-dev-qa-db-ja.com

ハッシュにnil値を割り当てない

ルビーでゼロのときにハッシュに物事を割り当てるための速記またはベストプラクティスはありますか?たとえば、私の問題は、これを構築するために別のハッシュを使用していて、その中の何かがnilの場合、それをそのままにするのではなく、そのキーにnilを割り当てることです。これが発生する理由を理解しているので、私の解決策は次のとおりです。

hash1[:key] = hash2[:key] unless hash2[:key].nil?

キーが実際にnilを指しているhasに値を設定できないためです。 ({:key => nil}を持つハッシュよりも、空のハッシュが必要です。これは発生しません)

私の質問は、これを行うためのより良い方法はありますか?割り当ての最後にdelete_ifを実行したくありません。

17
Red

「unless」ステートメントを否定すると、少し短くなります

hash1[:key] = hash2[:key] if hash2[:key]   # same as   if ! hash2[:key].nil?

michaelまたはMarc-Andreによる他の回答で提案されているように、&&ステートメントで比較を行うこともできます。

それは本当にあなた次第です、あなたが感じるものはあなたにとって最も読みやすいです。設計上、問題を解決する方法は常にRuby)にあります。

Hash2を変更することもできます:

hash1 = hash2.reject{|k,v| v.nil?}

hash2.reject!{|k,v| v.nil?}   # even shorter, if in-place editing of hash2

これにより、hash2からキーと値のペア:key => nilが削除されます(rejectを使用する場合はその場で!)

20
Tilo

私はこれが一番好きで、ループと条件付きオーバーライドをすべて1行で実行します!

h1 = {:foo => 'foo', :bar => 'bar'}
h2 = {:foo => 'oof', :bar => nil}

h1.merge!(h2) { |key, old_val, new_val| new_val.nil? ? old_val : new_val }

#=> {:foo => 'oof', :bar => 'bar'}

これにより、h1のすべての値が、キーが同じでh2の値がnilではないh2の値に置き換えられます。

4
bkempner

このようなものはどうですか?

hash2.each_pair do |key, value|
  next if value.nil?
  hash1[key] = value
end

割り当てを1つだけ行う場合、これにより数文字が削減される可能性があります。

hash2[:key] && hash1[:key] = hash2[:key]

私の最初の例は、もう少し削ることもできます。

hash2.each_pair{ |k,v| v && hash1[k] = v }

最初のものが最も読みやすく、理解しやすいと思います。また、例2と例3は、falseと評価されるもの(nilまたはfalse)をスキップします。この最後の例は1行で、false値をスキップしません。

hash2.each_pair{ |k,v| v.nil? || hash1[k] = v }
3
Carl Zulauf

それが本当に良いかどうかはわかりませんが

hash2[:key] && hash[:key] = hash2[:key]

動作する可能性があります。これがfalsenilで同じように動作することに注意してください。

!hash2[:key].nil? && hash[:key] = hash2[:key]

の方がいい。このすべては、:keyは、制御できない任意の値になります。

3
Michael Kohl

ベストプラクティスは、nil値をハッシュにコピーすることだと思います。オプション:foo => nilを渡すと、それは何かを意味する可能性があり、たとえば、デフォルトの:foo42をオーバーライドする必要があります。これにより、デフォルトでtrueに設定するオプションを簡単に作成できますが、そのような場合はfetchを使用する必要があります。

opt = hash.fetch(:do_cool_treatment, true) # => will be true if key is not present

nilfalseなど、値をコピーする方法はたくさんあります。

単一のキーの場合、ルックアップの代わりにhas_key?を使用できます。

hash1[:key] = hash2[:key] if hash2.has_key? :key

すべての(または多くの)キーには、merge!を使用します。

hash1.merge!(hash2)

hash2のいくつかのキーに対してのみこれを実行する場合は、次のようにスライスできます。

hash1.merge!(hash2.slice(:key, ...))

OK、それで、より多くの制御が必要なためにマージが機能しない場合:

hash1[:key] = hash2.fetch(:key, hash1[:key])

これにより、hash1の:keyが存在しない場合を除き、hash2に設定されます。その場合、hash1のキーであるデフォルト値(フェッチする2番目の引数)が使用されます

1
Jesse Wolgamott

これをイニシャライザーに追加しますhash.rb

class Hash
  def set_safe(key,val)
    if val && key
      self[key] = val
    end
  end
end

使用する

hash = {}
hash.set_safe 'key', value_or_nil
0
comonitos