Pergunta

Eu gostaria de substituir cada value em um hash com value.some_method.

Por exemplo, para um dado um hash simples:

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

cada valor deve ser .upcased, por isso se parece com:

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

Eu tentei #collect e #map mas sempre apenas obter matrizes de volta. Existe uma maneira elegante de fazer isso?

Atualizar

Droga, eu esqueci: O hash é uma variável de instância que não deve ser alterado. Preciso de um novo hash com os valores alterados, mas prefere não definir essa variável explícita e, em seguida, um loop sobre o hash preenchê-lo. Algo como:

new_hash = hash.magic{ ... }
Foi útil?

Solução

my_hash.each { |k, v| my_hash[k] = v.upcase } 

ou, se você preferir fazê-lo de forma não destrutiva, e retornar um novo hash em vez de modificar my_hash:

a_new_hash = my_hash.inject({}) { |h, (k, v)| h[k] = v.upcase; h } 

Esta última versão tem a vantagem adicional de que você poderia transformar as chaves também.

Outras dicas

Desde ruby 2.4.0 você pode usar nativa Hash#transform_values método:

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

Há também destrutiva Hash#transform_values! versão.

Você pode coletar os valores, e convertê-lo de Array para Hash novamente.

Como esta:

config = Hash[ config.collect {|k,v| [k, v.upcase] } ]

Isso vai fazê-lo:

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

Ao contrário de inject a vantagem é que você não está em necessidade de retornar o hash novamente dentro do bloco.

Tente esta função:

h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.

Há um método para que em ActiveSupport v4.2.0. É chamado transform_values e, basicamente, apenas executa um bloco para cada valor de par de chaves.

Uma vez que eles estão fazendo isso com um each Eu acho que não há nenhuma maneira melhor do que para percorrer.

hash = {sample: 'gach'}

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

Update:

Desde o Ruby 2.4.0 você pode nativamente usar #transform_values e #transform_values! .

eu faço algo como isto:

new_hash = Hash [* original_hash.collect {| chave, valor | [Chave, valor + 1]}. Achatar]

Isso fornece as instalações para transformar a chave ou valor através de qualquer expressão também (e é não-destrutivo, é claro).

Você pode querer dar um passo adiante e fazer isso em um hash aninhado. Certamente isso acontece uma quantidade justa com projetos Rails.

Aqui está um código para garantir uma params hash é em 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  

Ruby tem o método tap ( 1.8.7 , 1.9.3 e < a href = "http://ruby-doc.org/core-2.1.0/Object.html#method-i-tap" rel = "nofollow"> 2.1.0 ) que é muito útil para coisas como isso.

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"}

Se você sabe que os valores são strings, você pode chamar o substituir método sobre eles, enquanto no ciclo: desta forma você vai alterar o valor

.

Altohugh esta se limita ao caso em que os valores são strings e, portanto, não responde a pergunta totalmente, eu pensei que pode ser útil para alguém.

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"}

Rails específica de

No caso de alguém só precisa chamar o método to_s para cada um dos valores e não está usando Rails 4.2 (que inclui método transform_values link ), você pode fazer o seguinte:

original_hash = { :a => 'a', :b => BigDecimal('23.4') }
#=> {:a=>"a", :b=>#<BigDecimal:5c03a00,'0.234E2',18(18)>}
JSON(original_hash.to_json)
#=> {"a"=>"a", "b"=>"23.4"}

. Nota: O uso de biblioteca 'json' é necessária

Nota 2: Isto irá transformar chaves em strings bem

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top