Не присваивать ноль значения хешу - PullRequest
17 голосов
/ 30 ноября 2011

Есть ли короткая рука или лучшая практика для присвоения вещей хешу, когда они равны нулю в рубине?Например, моя проблема в том, что я использую другой хеш для создания этого и, если что-то в нем есть nil, он присваивает nil этому ключу, а не просто оставляет его в покое.Я понимаю, почему это происходит, поэтому мое решение было:

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

Поскольку у меня не может быть значения в has, где ключ фактически указывает на ноль.(Я бы предпочел иметь пустой хеш, чем тот, который имеет {: key => nil}, этого не может быть)

Мой вопрос был бы: есть ли лучший способ сделать это?Я не хочу делать delete_if в конце назначений.

Ответы [ 7 ]

20 голосов
/ 30 ноября 2011

немного короче, если вы отрицаете утверждение "исключение"

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

, вы также можете выполнить сравнение в выражении &&, как предложено в других ответах Михаэля или Марка-Андре

Это действительно зависит от вас, то, что вы считаете наиболее читабельным для вас.В Ruby всегда есть несколько способов решить проблему.

Вы также можете изменить hash2:

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

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

, чтобы удалить пары ключ / значение: key => nil изhash2 (на месте, если вы используете reject!)

4 голосов
/ 30 ноября 2011

Мне нравится это лучше всего, циклическое и условное переопределение всего в одной строке!

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, где ключи одинаковы, а значение h2 не равно nil.

3 голосов
/ 30 ноября 2011

Я считаю, что лучше всего скопировать значение nil в хеш.Если вы передаете опцию :foo => nil, это может что-то значить и должно переопределить значение по умолчанию :foo, например, 42.Это также упрощает использование опций, которые по умолчанию должны иметь значение true, хотя следует использовать fetch в следующих случаях:

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

Существует множество способов копирования значений, включая nil илиfalse.

Для одного ключа вы можете использовать has_key? вместо поиска:

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

Для всех (или многих) клавиш используйте merge!:

hash1.merge!(hash2)

Если вы хотите сделать это только для пары клавиш hash2, вы можете нарезать ее:

hash1.merge!(hash2.slice(:key, ...))
3 голосов
/ 30 ноября 2011

Я не уверен, что так лучше, но

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

может работать. Обратите внимание, что это будет работать одинаково для false и nil, если это не то, что вы хотите

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

было бы лучше. Все это при условии, что :key будет произвольным значением, которое вы не можете контролировать.

3 голосов
/ 30 ноября 2011

Как насчет этого?

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

Если вы выполняете только одно задание, это может сбрить несколько символов:

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

Мой первый пример также можно побрить немного дальше:

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

Я думаю, что первое легче всего читать / понимать. Кроме того, примеры 2 и 3 пропускают все, что оценивается как ложное (nil или false). Этот последний пример состоит из одной строки и не пропускает значения false:

hash2.each_pair{ |k,v| v.nil? || hash1[k] = v }
1 голос
/ 30 ноября 2011

ОК, поэтому, если слияние не работает, потому что вы хотите больше контроля:

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

Это установит hash1's: ключ для hash2, если он не существует. В этом случае он будет использовать значение по умолчанию (2-й аргумент для выборки), которое является ключом хеш-1

0 голосов
/ 28 мая 2015

Добавьте это к вашим инициализаторам hash.rb

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

use

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