Не присваивать хэшу значения nil


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

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

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

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

7 14

7 ответов:

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

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

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

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

Вы также можете изменить хэш2:

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

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

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

Я не уверен, что это действительно лучше, но

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

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

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

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

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

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 в хэш. Если кто-то передает опцию :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, ...))

Как насчет чего-то вроде этого?

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 пропустят все, что дает оценку false (nil или false). Этот последний пример является одной строкой и не пропускает значения false:

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

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

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

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

Добавьте это в хэш инициализаторов .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