ハッシュ内の各value
をvalue.some_method
に置き換えたいと思います。
たとえば、単純なハッシュが与えられた場合:
{"a" => "b", "c" => "d"}`
すべての値は.upcase
dである必要があるため、次のようになります。
{"a" => "B", "c" => "D"}
#collect
と#map
を試しましたが、常に配列を戻すだけです。これを行うエレガントな方法はありますか?
UPDATE
くそー、忘れてしまった:ハッシュは変更すべきではないインスタンス変数にあります。変更された値を持つ新しいハッシュが必要ですが、その変数を明示的に定義してから、それを埋めるハッシュをループすることを望まないでしょう。何かのようなもの:
new_hash = hash.magic{ ... }
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 }
この最後のバージョンには、キーも変換できるという追加の利点があります。
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!
バージョンもあります。
値を収集し、配列からハッシュに再度変換できます。
このような:
config = Hash[ config.collect {|k,v| [k, v.upcase] } ]
これはそれを行います:
my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }
inject
とは対照的に、ブロック内で再度ハッシュを返す必要がないという利点があります。
この機能を試してください:
h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.
そのためのメソッドが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!
を使用できます。
レール固有
誰かが各値に対して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:これにより、キーも文字列に変換されます
私はこのようなことをします:
new_hash =ハッシュ[* original_hash.collect {| key、value | [key、value + 1]}。flatten]
これにより、任意の式を使用してキーまたは値を変換する機能も提供されます(もちろん、非破壊的です)。
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プロジェクトでかなり発生します。
以下は、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
値が文字列であることがわかっている場合は、サイクル中に replace メソッドを呼び出すことができます。この方法で値を変更します。
これは、値が文字列である場合に限られているため、質問に完全には答えられず、誰かに役立つと思いました。