web-dev-qa-db-ja.com

ハッシュ値を変更するには?

ハッシュ内の各valuevalue.some_methodに置き換えたいと思います。

たとえば、単純なハッシュが与えられた場合:

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

すべての値は.upcasedである必要があるため、次のようになります。

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

#collect#mapを試しましたが、常に配列を戻すだけです。これを行うエレガントな方法はありますか?

UPDATE

くそー、忘れてしまった:ハッシュは変更すべきではないインスタンス変数にあります。変更された値を持つ新しいハッシュが必要ですが、その変数を明示的に定義してから、それを埋めるハッシュをループすることを望まないでしょう。何かのようなもの:

new_hash = hash.magic{ ... }
116
Adam Nonymous
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 } 

この最後のバージョンには、キーも変換できるという追加の利点があります。

205
kch

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! バージョンもあります。

85
potashin

値を収集し、配列からハッシュに再度変換できます。

このような:

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

これはそれを行います:

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

injectとは対照的に、ブロック内で再度ハッシュを返す必要がないという利点があります。

22
Konrad Reiche

この機能を試してください:

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

そのためのメソッドがActiveSupportv4.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! を使用できます。

10
schmijos

レール固有

誰かが各値に対してto_sメソッドを呼び出すだけで、Rails 4.2(transform_values method link を含む)を使用していない場合、次のことができます。

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

注:「json」ライブラリーの使用が必要です。

注2:これにより、キーも文字列に変換されます

1
lllllll

私はこのようなことをします:

new_hash =ハッシュ[* original_hash.collect {| key、value | [key、value + 1]}。flatten]

これにより、任意の式を使用してキーまたは値を変換する機能も提供されます(もちろん、非破壊的です)。

1
Cory Chamblin
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
cnst

さらに一歩進んで、ネストされたハッシュでこれを行うことができます。確かに、これは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  
1
Tokumine

Rubyにはtapメソッド( 1.8.71.9. および 2.1. )があり、このようなものに非常に役立ちます。

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
Nate

値が文字列であることがわかっている場合は、サイクル中に replace メソッドを呼び出すことができます。この方法で値を変更します。

これは、値が文字列である場合に限られているため、質問に完全には答えられず、誰かに役立つと思いました。

1
reallynice