Ruby에서 해시의 모든 키 이름을 우아하게 바꾸는 방법은 무엇입니까? [복제]
이 질문에 이미 답변이 있습니다.
Ruby 해시가 있습니다.
ages = { "Bruce" => 32,
"Clark" => 28
}
대체 이름의 다른 해시가 있다고 가정하면 모든 키의 이름을 바꾸는 우아한 방법이 있습니까?
ages = { "Bruce Wayne" => 32,
"Clark Kent" => 28
}
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
ages.map {|k, v| [mappings[k], v] }.to_h
Jörg W Mittag의 답변이 마음에 들었지만 개선 할 수 있습니다.
현재 해시의 키 이름을 바꾸고 이름이 바뀐 키로 새 해시를 만들지 않으려면 다음 스 니펫이 정확히 수행합니다.
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
ages.keys.each { |k| ages[ mappings[k] ] = ages.delete(k) if mappings[k] }
ages
필요한 키의 이름 만 바꾸는 장점도 있습니다.
성능 고려 사항 :
를 기반으로 틴 남자 의 대답, 내 대답은 약 20 % 더 빠른 르그 W MITTAG의 대답보다 해시에 대한 두 개의 키. 특히 이름을 바꿀 키가 몇 개만있는 경우 키가 많은 해시의 경우 더 높은 성능을 얻을 수 있습니다.
each_with_object
Ruby에서도 활용도가 낮은 방법이 있습니다.
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = { "Bruce" => "Bruce Wayne", "Clark" => "Clark Kent" }
ages.each_with_object({}) { |(k, v), memo| memo[mappings[k]] = v }
더 빠른 것이 무엇인지 확인하려면 :
require 'fruity'
AGES = { "Bruce" => 32, "Clark" => 28 }
MAPPINGS = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
def jörg_w_mittag_test(ages, mappings)
Hash[ages.map {|k, v| [mappings[k], v] }]
end
require 'facets/hash/rekey'
def tyler_rick_test(ages, mappings)
ages.rekey(mappings)
end
def barbolo_test(ages, mappings)
ages.keys.each { |k| ages[ mappings[k] ] = ages.delete(k) if mappings[k] }
ages
end
class Hash
def tfr_rekey(h)
dup.tfr_rekey! h
end
def tfr_rekey!(h)
h.each { |k, newk| store(newk, delete(k)) if has_key? k }
self
end
end
def tfr_test(ages, mappings)
ages.tfr_rekey mappings
end
class Hash
def rename_keys(mapping)
result = {}
self.map do |k,v|
mapped_key = mapping[k] ? mapping[k] : k
result[mapped_key] = v.kind_of?(Hash) ? v.rename_keys(mapping) : v
result[mapped_key] = v.collect{ |obj| obj.rename_keys(mapping) if obj.kind_of?(Hash)} if v.kind_of?(Array)
end
result
end
end
def greg_test(ages, mappings)
ages.rename_keys(mappings)
end
compare do
jörg_w_mittag { jörg_w_mittag_test(AGES.dup, MAPPINGS.dup) }
tyler_rick { tyler_rick_test(AGES.dup, MAPPINGS.dup) }
barbolo { barbolo_test(AGES.dup, MAPPINGS.dup) }
greg { greg_test(AGES.dup, MAPPINGS.dup) }
end
출력되는 내용 :
Running each test 1024 times. Test will take about 1 second.
barbolo is faster than jörg_w_mittag by 19.999999999999996% ± 10.0%
jörg_w_mittag is faster than greg by 10.000000000000009% ± 10.0%
greg is faster than tyler_rick by 30.000000000000004% ± 10.0%
주의 : barbell의 솔루션은을 사용하므로 결과가 nil 값 if mappings[k]
이면 mappings[k]
결과 해시가 잘못됩니다 .
중첩 된 해시 및 배열을 처리하기 위해 클래스를 원숭이 패치했습니다.
# Netsted Hash:
#
# str_hash = {
# "a" => "a val",
# "b" => "b val",
# "c" => {
# "c1" => "c1 val",
# "c2" => "c2 val"
# },
# "d" => "d val",
# }
#
# mappings = {
# "a" => "apple",
# "b" => "boss",
# "c" => "cat",
# "c1" => "cat 1"
# }
# => {"apple"=>"a val", "boss"=>"b val", "cat"=>{"cat 1"=>"c1 val", "c2"=>"c2 val"}, "d"=>"d val"}
#
class Hash
def rename_keys(mapping)
result = {}
self.map do |k,v|
mapped_key = mapping[k] ? mapping[k] : k
result[mapped_key] = v.kind_of?(Hash) ? v.rename_keys(mapping) : v
result[mapped_key] = v.collect{ |obj| obj.rename_keys(mapping) if obj.kind_of?(Hash)} if v.kind_of?(Array)
end
result
end
end
매핑 해시가 데이터 해시보다 작 으면 매핑을 대신 반복합니다. 이것은 큰 해시에서 몇 개의 필드 이름을 바꾸는 데 유용합니다.
class Hash
def rekey(h)
dup.rekey! h
end
def rekey!(h)
h.each { |k, newk| store(newk, delete(k)) if has_key? k }
self
end
end
ages = { "Bruce" => 32, "Clark" => 28, "John" => 36 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
p ages.rekey! mappings
You may wish to use Object#tap to avoid the need to return ages
after the keys have been modified:
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
ages.tap {|h| h.keys.each {|k| (h[mappings[k]] = h.delete(k)) if mappings.key?(k)}}
#=> {"Bruce Wayne"=>32, "Clark Kent"=>28}
The Facets gem provides a rekey
method that does exactly what you're wanting.
As long as you're okay with a dependency on the Facets gem, you can pass a hash of mappings to rekey
and it will return a new hash with the new keys:
require 'facets/hash/rekey'
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
ages.rekey(mappings)
=> {"Bruce Wayne"=>32, "Clark Kent"=>28}
If you want to modify ages hash in place, you can use the rekey!
version:
ages.rekey!(mappings)
ages
=> {"Bruce Wayne"=>32, "Clark Kent"=>28}
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
ages = mappings.inject({}) {|memo, mapping| memo[mapping[1]] = ages[mapping[0]]; memo}
puts ages.inspect
>> x={ :a => 'qwe', :b => 'asd'}
=> {:a=>"qwe", :b=>"asd"}
>> rename={:a=>:qwe}
=> {:a=>:qwe}
>> rename.each{|old,new| x[new] = x.delete old}
=> {:a=>:qwe}
>> x
=> {:b=>"asd", :qwe=>"qwe"}
This would loop just through renames hash.
I used this to allow "friendly" names in a Cucumber table to be parsed into class attributes such that Factory Girl could create an instance:
Given(/^an organization exists with the following attributes:$/) do |table|
# Build a mapping from the "friendly" text in the test to the lower_case actual name in the class
map_to_keys = Hash.new
table.transpose.hashes.first.keys.each { |x| map_to_keys[x] = x.downcase.gsub(' ', '_') }
table.transpose.hashes.each do |obj|
obj.keys.each { |k| obj[map_to_keys[k]] = obj.delete(k) if map_to_keys[k] }
create(:organization, Rack::Utils.parse_nested_query(obj.to_query))
end
end
For what it's worth, the Cucumber table looks like this:
Background:
And an organization exists with the following attributes:
| Name | Example Org |
| Subdomain | xfdc |
| Phone Number | 123-123-1234 |
| Address | 123 E Walnut St, Anytown, PA 18999 |
| Billing Contact | Alexander Hamilton |
| Billing Address | 123 E Walnut St, Anytown, PA 18999 |
And map_to_keys
looks like this:
{
"Name" => "name",
"Subdomain" => "subdomain",
"Phone Number" => "phone_number",
"Address" => "address",
"Billing Contact" => "billing_contact",
"Billing Address" => "billing_address"
}
참고URL : https://stackoverflow.com/questions/4137824/how-to-elegantly-rename-all-keys-in-a-hash-in-ruby
'developer tip' 카테고리의 다른 글
Phonegap이있는 iOS 7 상태 표시 줄 (0) | 2020.09.02 |
---|---|
react-router 페이지로 돌아 가기 히스토리를 어떻게 구성합니까? (0) | 2020.09.02 |
LocalDate에 대한 문자열 (0) | 2020.09.02 |
라 라벨 스타일 시트와 자바 스크립트가 기본 경로가 아닌 경우로드되지 않습니다. (0) | 2020.09.02 |
Visual Studio의 빌드를 매우 장황하게 만들려면 어떻게해야합니까? (0) | 2020.09.02 |