Не присваивать значения хэш хэш
Есть ли короткая рука или лучшая практика для назначения вещей хэшу, когда они ноль в рубине? Например, моя проблема заключается в том, что я использую другой хеш, чтобы построить это, и если что-то в нем равно нулю, он назначает nil этому ключу, а не просто оставляет его в покое. Я понимаю, почему это происходит, поэтому я решил:
hash1[:key] = hash2[:key] unless hash2[:key].nil?
Потому что я не могу иметь значение в том, где ключ фактически указывает на нуль. (Я предпочел бы иметь пустой хэш, чем тот, который имеет {: key = > nil}, что не может произойти)
Мой вопрос будет, есть ли лучший способ сделать это? Я не хочу делать delete_if в конце назначений.
Ответы
Ответ 1
немного короче, если вы отрицаете утверждение "если"
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!)
Ответ 2
Я не уверен, что это действительно лучше, но
hash2[:key] && hash[:key] = hash2[:key]
может работать. Обратите внимание, что это будет вести себя одинаково для false
и nil
, если это не то, что вы хотите
!hash2[:key].nil? && hash[:key] = hash2[:key]
было бы лучше. Все это предполагает, что :key
будет произвольным значением, которое вы не можете контролировать.
Ответ 3
Я считаю, что лучше всего скопировать значение nil
в хэш. Если передать опцию :foo => nil
, это может означать что-то и, например, переопределить значение по умолчанию :foo
of 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, ...))
Ответ 4
Мне нравится это лучший, цикл и условное переопределение всего в одну строку!
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 не равно нулю.
Ответ 5
Как насчет чего-то подобного?
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 }
Ответ 6
ОК, поэтому, если слияние не работает, потому что вам нужно больше управления:
hash1[:key] = hash2.fetch(:key, hash1[:key])
Это установит hash1: ключ hash2, если он не существует. В этом случае он будет использовать значение по умолчанию (2-й аргумент для извлечения), который является символом hash1
Ответ 7
Добавьте это в свои инициализаторы 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