Как изменить значения хэша? - PullRequest
113 голосов
/ 01 мая 2009

Я бы хотел заменить каждый value в хэше на value.some_method.

Например, для данного простого хэша:

{"a" => "b", "c" => "d"}` 

каждое значение должно быть .upcase d, поэтому оно выглядит следующим образом:

{"a" => "B", "c" => "D"}

Я пытался #collect и #map, но всегда просто возвращал массивы. Есть ли элегантный способ сделать это?

ОБНОВЛЕНИЕ

Черт, я забыл: хеш находится в переменной экземпляра, которую нельзя менять. Мне нужен новый хэш с измененными значениями, но я бы предпочел не определять эту переменную явно, а затем перебирать ее, заполняя ее. Что-то вроде:

new_hash = hash.magic{ ... }

Ответы [ 12 ]

202 голосов
/ 01 мая 2009
my_hash.each { |k, v| my_hash[k] = v.upcase } 

или, если вы предпочитаете делать это неразрушающим образом, и вместо изменения my_hash:

вернуть новый хеш
a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h } 

Эта последняя версия имеет дополнительное преимущество, заключающееся в том, что вы также можете трансформировать ключи.

77 голосов
/ 09 января 2017

Поскольку ruby 2.4.0, вы можете использовать собственный Hash#transform_values метод:

hash = {"a" => "b", "c" => "d"}
new_hash = hash.transform_values(&:upcase)
# => {"a" => "B", "c" => "D"}

Существует также деструктивная Hash#transform_values! версия.

32 голосов
/ 09 сентября 2011

Вы можете собрать значения и снова преобразовать их из массива в хэш.

Как это:

config = Hash[ config.collect {|k,v| [k, v.upcase] } ]
22 голосов
/ 10 октября 2013

Это сделает это:

my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }

В отличие от inject преимущество заключается в том, что вам больше не нужно возвращать хеш внутри блока.

10 голосов
/ 01 мая 2009

Попробуйте эту функцию:

h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.
9 голосов
/ 15 июля 2015

Для этого есть ActiveSupport v4.2.0. Он называется transform_values и в основном просто выполняет блок для каждой пары ключ-значение.

Поскольку они делают это с each, я думаю, что нет лучшего способа, чем перебрать.

hash = {sample: 'gach'}

result = {}
hash.each do |key, value|
  result[key] = do_stuff(value)
end

Обновление:

Начиная с Ruby 2.4.0, вы можете использовать #transform_values и #transform_values!.

1 голос
/ 30 декабря 2015
new_hash = old_hash.merge(old_hash) do |_key, value, _value|
             value.upcase
           end

# old_hash = {"a" => "b", "c" => "d"}
# new_hash = {"a" => "B", "c" => "D"}
1 голос
/ 18 сентября 2015

Если вы знаете, что значения являются строками, вы можете вызвать метод replace для них во время цикла: таким образом вы измените значение.

Хотя это ограничено случаем, когда значения являются строками и, следовательно, не дает полного ответа на вопрос, я подумал, что это может быть кому-то полезно.

1 голос
/ 10 февраля 2014

В Ruby есть метод tap ( 1.8.7 , 1.9.3 и 2.1.0 ), который очень полезен для подобных вещей.

original_hash = { :a => 'a', :b => 'b' }
original_hash.clone.tap{ |h| h.each{ |k,v| h[k] = v.upcase } }
# => {:a=>"A", :b=>"B"}
original_hash # => {:a=>"a", :b=>"b"}
1 голос
/ 13 сентября 2010

Вы можете пойти дальше и сделать это на вложенном хэше. Конечно, это случается изрядно с проектами Rails.

Вот некоторый код, чтобы гарантировать, что хэш params находится в UTF-8:

  def convert_hash hash
    hash.inject({}) do |h,(k,v)|
      if v.kind_of? String
        h[k] = to_utf8(v) 
      else
        h[k] = convert_hash(v)
      end
      h
    end      
  end    

  # Iconv UTF-8 helper
  # Converts strings into valid UTF-8
  #
  # @param [String] untrusted_string the string to convert to UTF-8
  # @return [String] your string in UTF-8
  def to_utf8 untrusted_string=""
    ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
    ic.iconv(untrusted_string + ' ')[0..-2]
  end  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...