값 앞뒤에 '%'를 추가하기 위해 해시의 모든 값을 변경하고 싶습니다.
{ :a=>'a' , :b=>'b' }
로 변경해야합니다
{ :a=>'%a%' , :b=>'%b%' }
가장 좋은 방법은 무엇입니까?
값 앞뒤에 '%'를 추가하기 위해 해시의 모든 값을 변경하고 싶습니다.
{ :a=>'a' , :b=>'b' }
로 변경해야합니다
{ :a=>'%a%' , :b=>'%b%' }
가장 좋은 방법은 무엇입니까?
답변:
실제 문자열 자체가 제자리에서 변경되도록하려면 (같은 문자열 객체에 대한 다른 참조에 영향을 줄 수 있으며)
# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }
해시를 제자리에서 변경하고 싶지만 문자열에 영향을 미치지 않으려면 (새 문자열을 얻으려면) :
# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |key,str| my_hash[key] = "%#{str}%" }
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
새로운 해시를 원한다면 :
# Ruby 1.8.6+
new_hash = Hash[*my_hash.map{|k,str| [k,"%#{str}%"] }.flatten]
# Ruby 1.8.7+
new_hash = Hash[my_hash.map{|k,str| [k,"%#{str}%"] } ]
Hash.[]
배열 쌍의 배열을 허용하지 않으므로 짝수 개의 직접 인수가 필요합니다 (따라서 앞뒤로).
Hash#each
는 키와 값을 모두 블록에 제공합니다. 이 경우 키에 신경 쓰지 않았으므로 유용한 이름은 지정하지 않았습니다. 변수 이름은 밑줄로 시작 할 수 있으며, 실제로있을 수 있습니다 단지 밑줄. 이 작업을 수행하면 성능 이점이 없으며 첫 번째 블록 값으로 아무것도하지 않는다는 미묘한 자체 문서 참고 사항입니다.
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
블록에서 해시를 반환해야
Ruby 2.1 이상에서는 할 수 있습니다
{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
#transform_values!
하는 경우 sschmeck ( stackoverflow.com/a/41508214/6451879 )에서 지적한 것처럼 사용하기가 훨씬 쉽습니다 .
Ruby 2.4에서는 Hash#transform_values!
사용할 수 있는 메소드를 도입했습니다 .
{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"}
Hash#transform_values
수신기를 수정하지 않는 (뱅없이 )도 있습니다 . 그렇지 않으면 좋은 답변 감사합니다!
해시 값을 수정하는 가장 좋은 방법은
hash.update(hash){ |_,v| "%#{v}%" }
적은 코드와 명확한 의도. 또한 변경해야하는 값 이상의 새 객체가 할당되지 않기 때문에 더 빠릅니다.
gsub!
.
k
, 사용 _
대신.
좀 더 읽기 쉬운 map
단일 요소 해시 배열 reduce
로merge
the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Hash[the_hash.map { |key,value| [key, "%#{value}%"] }]
Array
(for map
)을 만든 다음 a 를 만듭니다 Hash
. 그런 다음 축소 작업의 각 단계에서 "메모리"를 복제 Hash
하고 새 키-값 쌍을 추가합니다. 결승전을 수정하려면 최소한 :merge!
in reduce
을 사용 하십시오 Hash
. 그리고 결국, 당신은 기존 객체의 값을 수정하지 않고 새로운 객체를 만듭니다. 이것은 질문이 아닙니다.
nil
경우 반환the_hash
이 작업에는 새로운 'Rails way'방법이 있습니다. :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values
Hash#transform_values
. 이것은 지금부터가는 길이어야합니다.
원본에 부작용을 일으키지 않는 한 가지 방법 :
h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
Hash # map 은 Hash.map
해시를 반환하지 않는 이유 (결과 [key,value]
쌍의 배열이 새 해시로 변환되는 이유 )를 설명하고 동일한 일반 패턴에 대한 대체 접근 방식을 제공 하므로 흥미롭게 읽힐 수 있습니다 .
행복한 코딩.
[면책 조항 : Hash.map
Ruby 2.x에서 의미가 변경 되는지 확실하지 않습니다 ]
Hash.map
는 Ruby 2.x에서 시맨틱이 변경 되는지 알고 있습니까?
my_hash.each do |key, value|
my_hash[key] = "%#{value}%"
end
each_with_object
Ruby 1.9 (IIRC)에는 이름에 직접 액세스 할 필요 가 없으며 Map#merge
작동 할 수도 있습니다. 복잡한 세부 사항이 어떻게 다른지 잘 모르겠습니다.
다음과 같이 RSpec으로 테스트 한 후 :
describe Hash do
describe :map_values do
it 'should map the values' do
expect({:a => 2, :b => 3}.map_values { |x| x ** 2 }).to eq({:a => 4, :b => 9})
end
end
end
다음과 같이 Hash # map_values를 구현할 수 있습니다.
class Hash
def map_values
Hash[map { |k, v| [k, yield(v)] }]
end
end
그런 다음이 기능을 다음과 같이 사용할 수 있습니다.
{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}
어떤 인플레 이스 변형이 가장 빠른지 궁금하다면 다음과 같습니다.
Calculating -------------------------------------
inplace transform_values! 1.265k (± 0.7%) i/s - 6.426k in 5.080305s
inplace update 1.300k (± 2.7%) i/s - 6.579k in 5.065925s
inplace map reduce 281.367 (± 1.1%) i/s - 1.431k in 5.086477s
inplace merge! 1.305k (± 0.4%) i/s - 6.630k in 5.080751s
inplace each 1.073k (± 0.7%) i/s - 5.457k in 5.084044s
inplace inject 697.178 (± 0.9%) i/s - 3.519k in 5.047857s