Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 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