Ruby에서 해시를 어떻게 복사합니까?
나는 내가 약간의 루비 초보자임을 인정할 것입니다 (지금 레이크 스크립트 작성). 대부분의 언어에서 사본 생성자를 쉽게 찾을 수 있습니다. 30 분 동안 검색하면 루비에서 찾지 못했습니다. 원본 인스턴스에 영향을 미치지 않고 해시 복사본을 만들려고합니다.
의도 한대로 작동하지 않는 일부 예상되는 방법 :
h0 = { "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1=Hash.new(h0)
h2=h1.to_hash
그 동안 나는이 우아한 해결 방법에 의지했습니다.
def copyhash(inputhash)
h = Hash.new
inputhash.each do |pair|
h.store(pair[0], pair[1])
end
return h
end
이 clone
방법은 얕은 복사 를 수행하는 Ruby의 표준 내장 방법입니다 .
irb(main):003:0> h0 = {"John" => "Adams", "Thomas" => "Jefferson"}
=> {"John"=>"Adams", "Thomas"=>"Jefferson"}
irb(main):004:0> h1 = h0.clone
=> {"John"=>"Adams", "Thomas"=>"Jefferson"}
irb(main):005:0> h1["John"] = "Smith"
=> "Smith"
irb(main):006:0> h1
=> {"John"=>"Smith", "Thomas"=>"Jefferson"}
irb(main):007:0> h0
=> {"John"=>"Adams", "Thomas"=>"Jefferson"}
동작이 재정의 될 수 있습니다.
이 메서드에는 클래스 별 동작이있을 수 있습니다. 그렇다면, 그 행동은
#initialize_copy
클래스 의 방법 으로 문서화 될 것 입니다.
다른 사람들이 지적했듯이 clone
그렇게 할 것입니다. 주의하십시오 clone
해시의 얕은 복사본을 만듭니다. 즉 말하자면:
h1 = {:a => 'foo'}
h2 = h1.clone
h1[:a] << 'bar'
p h2 # => {:a=>"foobar"}
일어나는 일은 해시의 참조가 복사되고 있지만 참조가 참조하는 객체는 아닙니다.
깊은 사본을 원한다면 다음을 수행하십시오.
def deep_copy(o)
Marshal.load(Marshal.dump(o))
end
h1 = {:a => 'foo'}
h2 = deep_copy(h1)
h1[:a] << 'bar'
p h2 # => {:a=>"foo"}
deep_copy
마샬링 될 수있는 모든 개체에 적용됩니다. 대부분의 기본 제공 데이터 형식 (Array, Hash, String 등)을 마샬링 할 수 있습니다.
Marshalling 은 루비의 직렬화 이름입니다 . 마샬링을 사용하면 객체가 참조하는 객체가 일련의 바이트로 변환됩니다. 그런 다음 해당 바이트는 원본과 같은 다른 객체를 만드는 데 사용됩니다.
Rails를 사용하는 경우 다음을 수행 할 수 있습니다.
h1 = h0.deep_dup
http://apidock.com/rails/Hash/deep_dup
해시는 기존 해시에서 새 해시를 만들 수 있습니다.
irb(main):009:0> h1 = {1 => 2}
=> {1=>2}
irb(main):010:0> h2 = Hash[h1]
=> {1=>2}
irb(main):011:0> h1.object_id
=> 2150233660
irb(main):012:0> h2.object_id
=> 2150205060
I am also a newbie to Ruby and I faced similar issues in duplicating a hash. Use the following. I've got no idea about the speed of this method.
copy_of_original_hash = Hash.new.merge(original_hash)
As mentioned in Security Considerations section of Marshal documentation,
If you need to deserialize untrusted data, use JSON or another serialization format that is only able to load simple, ‘primitive’ types such as String, Array, Hash, etc.
Here is an example on how to do cloning using JSON in Ruby:
require "json"
original = {"John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
cloned = JSON.parse(JSON.generate(original))
# Modify original hash
original["John"] << ' Sandler'
p original
#=> {"John"=>"Adams Sandler", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}
# cloned remains intact as it was deep copied
p cloned
#=> {"John"=>"Adams", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}
Use Object#clone
:
h1 = h0.clone
(Confusingly, the documentation for clone
says that initialize_copy
is the way to override this, but the link for that method in Hash
directs you to replace
instead...)
you can use below to deep copy Hash objects.
deeply_copied_hash = Marshal.load(Marshal.dump(original_hash))
Since standard cloning method preserves the frozen state, it is not suitable for creating new immutable objects basing on the original object, if you would like the new objects be slightly different than the original (if you like stateless programming).
Clone is slow. For performance should probably start with blank hash and merge. Doesn't cover case of nested hashes...
require 'benchmark'
def bench Benchmark.bm do |b|
test = {'a' => 1, 'b' => 2, 'c' => 3, 4 => 'd'}
b.report 'clone' do
1_000_000.times do |i|
h = test.clone
h['new'] = 5
end
end
b.report 'merge' do
1_000_000.times do |i|
h = {}
h['new'] = 5
h.merge! test
end
end
b.report 'inject' do
1_000_000.times do |i|
h = test.inject({}) do |n, (k, v)|
n[k] = v;
n
end
h['new'] = 5
end
end
end
end
bench user system total ( real) clone 1.960000 0.080000 2.040000 ( 2.029604) merge 1.690000 0.080000 1.770000 ( 1.767828) inject 3.120000 0.030000 3.150000 ( 3.152627)
Since Ruby has a million ways to do it, here's another way using Enumerable:
h0 = { "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1 = h0.inject({}) do |new, (name, value)|
new[name] = value;
new
end
This is a special case, but if you're starting with a predefined hash that you want to grab and make a copy of, you can create a method that returns a hash:
def johns
{ "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
end
h1 = johns
The particular scenario that I had was I had a collection of JSON-schema hashes where some hashes built off others. I was initially defining them as class variables and ran into this copy issue.
Alternative way to Deep_Copy that worked for me.
h1 = {:a => 'foo'}
h2 = Hash[h1.to_a]
This produced a deep_copy since h2 is formed using an array representation of h1 rather than h1's references.
참고URL : https://stackoverflow.com/questions/4157399/how-do-i-copy-a-hash-in-ruby
'IT' 카테고리의 다른 글
리포지토리를 가져온 후 생성 된 원격 브랜치에 대해 git-svn에 알리려면 어떻게해야합니까? (0) | 2020.05.13 |
---|---|
포크와 exec의 차이점 (0) | 2020.05.13 |
UINavigationController에 오른쪽 버튼을 추가하는 방법? (0) | 2020.05.13 |
스위프트에서 Float를 Int로 변환 (0) | 2020.05.13 |
JavaScript는 스크롤의 창 X / Y 위치를 얻습니다. (0) | 2020.05.13 |