मैं रूबी में एक हैश की नकल कैसे करूं?


197

मैं मानता हूँ कि मैं थोड़ा रूबी नौसिखिया हूँ (रेक स्क्रिप्ट लिखना, अब)। अधिकांश भाषाओं में, कॉपी कंस्ट्रक्टर को ढूंढना आसान है। आधे घंटे की खोज ने इसे माणिक में नहीं पाया। मैं हैश की एक प्रति बनाना चाहता हूं ताकि मूल उदाहरण को प्रभावित किए बिना मैं इसे संशोधित कर सकूं।

कुछ अपेक्षित विधियाँ जो उद्देश्य के अनुसार काम नहीं करती हैं:

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

यदि आप सादे Hashवस्तुओं के साथ काम कर रहे हैं , तो प्रदान किया गया उत्तर अच्छा है। यदि आप हाश जैसी वस्तुओं के साथ काम कर रहे हैं जो उन स्थानों से आती हैं जिन्हें आप नियंत्रित नहीं करते हैं, तो आपको यह विचार करना चाहिए कि क्या आप चाहते हैं कि हैश के साथ जुड़ा एकल वर्ग डुप्लिकेट हो या नहीं। देखें stackoverflow.com/questions/10183370/…
Sim

जवाबों:


223

cloneविधि रूबी के मानक, निर्मित रास्ता एक करना है उथले कॉपी :

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कक्षा की पद्धति के तहत प्रलेखित किया जाएगा ।


क्लोन ऑब्जेक्ट, बीटीडब्ल्यू पर एक विधि है, इसलिए इसमें सब कुछ एक्सेस है। यहां
डायलन लेसी

29
जो लोग अन्य उत्तर नहीं पढ़ रहे हैं उनके लिए यहां अधिक स्पष्ट टिप्पणी जोड़ना यह उथली प्रति है।
ग्रम्पासॉरस

#initialize_copy दस्तावेज़ीकरण हाश के लिए मौजूद नहीं है, भले ही हैश डॉक पेज रूबी- doc.org/core-1.9.3/Hash.html#method-i-initialize-copy
फिल्हाल

14
और अन्य रूबी शुरुआती के लिए, "उथले प्रति" का मतलब है कि पहले स्तर से नीचे की प्रत्येक वस्तु अभी भी एक संदर्भ है।
रॉब जूल

9
ध्यान दें कि यह मेरे लिए नेस्टेड हैश के लिए काम नहीं किया (जैसा कि अन्य उत्तरों में उल्लेख किया गया है)। मैंने इस्तेमाल किया Marshal.load(Marshal.dump(h))
भेशमार

178

जैसा कि दूसरों ने बताया है, 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किसी भी वस्तु के लिए काम करता है जिसे मार्शेल्ड किया जा सकता है। अधिकांश अंतर्निहित डेटा प्रकार (ऐरे, हैश, स्ट्रिंग, और सी।) को मार्शल किया जा सकता है।

क्रमांकन के लिए मार्शलिंग रूबी का नाम है । मार्शलिंग के साथ, ऑब्जेक्ट - यह संदर्भित वस्तुओं के साथ - बाइट्स की एक श्रृंखला में परिवर्तित हो जाता है; उन बाइट्स का उपयोग मूल जैसी दूसरी वस्तु बनाने के लिए किया जाता है।


यह अच्छा है कि आपने गहरी नकल के बारे में जानकारी प्रदान की है, लेकिन यह एक चेतावनी के साथ आना चाहिए कि इससे अनपेक्षित दुष्प्रभाव हो सकते हैं (उदाहरण के लिए, या तो हैश को संशोधित करना दोनों को संशोधित करता है)। एक हैश क्लोनिंग का मुख्य उद्देश्य मूल (अपरिवर्तनशीलता, आदि) के संशोधन को रोक रहा है।
। बढ़ई

6
@ K.Carpenter क्या यह उथली प्रति नहीं है जो मूल के हिस्सों को साझा करती है? डीप कॉपी, जैसा कि मैं समझता हूं, यह एक कॉपी है जो मूल के किसी भी हिस्से को साझा नहीं करता है, इसलिए एक को संशोधित करने से दूसरे को संशोधित नहीं किया जाएगा।
वेन कॉनराड

1
कितनी Marshal.load(Marshal.dump(o))गहरी नकल है? मैं वास्तव में समझ नहीं पा रहा हूं कि पर्दे के पीछे क्या होता है
मुंतसिर आलम

क्या इस पर प्रकाश डाला और साथ ही है कि यदि आप करते हैं h1[:a] << 'bar'आप मूल वस्तु को संशोधित (स्ट्रिंग h1 द्वारा की ओर इशारा किया [: एक]), लेकिन यदि आप ऐसा करने के लिए थे h1[:a] = "#{h1[:a]}bar"बजाय, आप बिंदु एक नया स्ट्रिंग वस्तु बनाने होता है, और h1[:a]उस पर है, जबकि h2[:a]यह है अभी भी पुराने (unmodified) स्ट्रिंग की ओर इशारा करते हैं।
मैक्स विलियम्स

@MuntasirAlam मैंने कुछ शब्द जोड़े जो मार्शालिंग करता है। मुझे आशा है कि वह मदद करेंगे।
वेन कॉनराड

73

यदि आप रेल का उपयोग कर रहे हैं तो आप कर सकते हैं:

h1 = h0.deep_dup

http://apidock.com/rails/Hash/deep_dup


2
रेल 3 के पास Hashes के भीतर डीप_डुपिंग सरणियों के साथ एक समस्या है। रेल 4 तय करता है।
pdobb

1
इस बिंदु के लिए धन्यवाद, मेरी हैश तब भी प्रभावित हुई जब
दुप्पटे

13

हैश एक मौजूदा हैश से एक नया हैश बना सकता है:

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

24
ध्यान दें कि इसमें #clone और #dup के समान गहरी कॉपी समस्या है।
forforf

3
@forforf सही है। यदि आप गहरी बनाम उथली प्रतिलिपि को नहीं समझते हैं, तो डेटा संरचनाओं को कॉपी करने का प्रयास न करें।
जेम्स मूर

5

मैं रूबी के लिए एक नौसिखिया भी हूं और मुझे हैश की नकल करने में इसी तरह के मुद्दों का सामना करना पड़ा। निम्न का उपयोग करें। मुझे इस विधि की गति के बारे में कोई जानकारी नहीं है।

copy_of_original_hash = Hash.new.merge(original_hash)

3

जैसा कि मार्शल डॉक्यूमेंटेशन के सुरक्षा विचार अनुभाग में वर्णित है ,

यदि आपको अविश्वासित डेटा की आवश्यकता नहीं है, तो JSON या किसी अन्य क्रमांकन प्रारूप का उपयोग करें जो केवल सरल, 'आदिम' प्रकार जैसे String, Array, Hash, आदि को लोड करने में सक्षम है।

यहाँ एक उदाहरण है कि रूबी में JSON का उपयोग करके क्लोनिंग कैसे करें:

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

1

उपयोग करें Object#clone:

h1 = h0.clone

(भ्रामक रूप से, cloneकहता है कि initialize_copyयह ओवरराइड करने का तरीका है, लेकिन उस तरीके का लिंक Hashआपको replaceइसके बजाय डायरेक्ट करने के लिए है ...)


1

चूंकि मानक क्लोनिंग विधि जमे हुए राज्य को संरक्षित करती है, इसलिए यह मूल वस्तु पर आधारित नई अपरिवर्तनीय वस्तुओं को बनाने के लिए उपयुक्त नहीं है, यदि आप चाहेंगे कि नई वस्तुएं मूल से थोड़ा अलग हों (यदि आप स्टेटलेस प्रोग्रामिंग पसंद करते हैं)।


1

क्लोन धीमा है। प्रदर्शन के लिए संभवतः खाली हैश और मर्ज के साथ शुरू होना चाहिए। नेस्टेड हैश के मामले को कवर नहीं करता है ...

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
  बेंच उपयोगकर्ता प्रणाली कुल (वास्तविक)
  क्लोन 1.960000 0.080000 2.040000 (2.029604)
  मर्ज 1.690000 0.080000 1.770000 (1.767828)
  इंजेक्शन 3.120000 0.030000 3.150000 (3.152627)
  

1

यह एक विशेष मामला है, लेकिन यदि आप एक पूर्वनिर्धारित हैश के साथ शुरू कर रहे हैं, जिसे आप हड़पना चाहते हैं और उसकी प्रतिलिपि बनाना चाहते हैं, तो आप एक ऐसा तरीका बना सकते हैं जो हैश लौटाता है:

def johns 
    {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
end

h1 = johns

मेरे पास जो विशेष परिदृश्य था, वह JSON- स्कीमा हैश का एक संग्रह था जहां कुछ हैश ने दूसरों को बनाया। मैं शुरू में उन्हें कक्षा चर के रूप में परिभाषित कर रहा था और इस कॉपी मुद्दे में भाग गया।


0

आप नीचे हैश ऑब्जेक्ट को कॉपी करने के लिए उपयोग कर सकते हैं।

deeply_copied_hash = Marshal.load(Marshal.dump(original_hash))

16
यह वेन कॉनराड के उत्तर का एक डुप्लिकेट है।
एंड्रयू ग्रिम

0

चूंकि रूबी के पास इसे करने के लिए एक लाख तरीके हैं, इसलिए यहां एन्युमरबल का उपयोग करने का एक और तरीका है:

h0 = {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1 = h0.inject({}) do |new, (name, value)| 
    new[name] = value;
    new 
end

-3

मेरे लिए काम करने वाले डीप_कॉपी का वैकल्पिक तरीका।

h1 = {:a => 'foo'} 
h2 = Hash[h1.to_a]

यह h_ के संदर्भ के बजाय h1 के एक सरणी प्रतिनिधित्व का उपयोग करके बनाई गई है, क्योंकि h2 एक deep_copy का उत्पादन किया।


3
होनहार लगता है, लेकिन काम नहीं करता है, यह एक और उथली प्रति है
जिन्टी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.