हश मान कैसे बदलें?


126

मैं valueएक के साथ एक हैश में प्रत्येक को बदलना चाहता हूं value.some_method

उदाहरण के लिए, किसी साधारण हैश के लिए:

{"a" => "b", "c" => "d"}` 

प्रत्येक मान .upcased होना चाहिए , इसलिए ऐसा दिखता है:

{"a" => "B", "c" => "D"}

मैंने कोशिश की #collectऔर #mapहमेशा बस वापस सरण मिलती है। क्या ऐसा करने का एक सुंदर तरीका है?

अपडेट करें

धिक्कार है, मैं भूल गया: हैश एक उदाहरण चर में है जिसे बदला नहीं जाना चाहिए। मुझे बदले हुए मूल्यों के साथ एक नए हैश की आवश्यकता है, लेकिन स्पष्ट रूप से उस चर को परिभाषित करने और फिर इसे भरने वाले हैश पर लूप नहीं करना पसंद करेंगे। कुछ इस तरह:

new_hash = hash.magic{ ... }

मेरे जवाब में दूसरा उदाहरण एक नया हैश देता है। उस पर टिप्पणी करें यदि आप चाहते हैं कि मैं उस जादू पर विस्तार करूं जो # विषय है।
दोपहर

जवाबों:


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

इस अंतिम संस्करण में अतिरिक्त लाभ है कि आप चाबियाँ भी बदल सकते हैं।


26
पहला सुझाव उचित नहीं है; एक ऊर्जावान तत्व को संशोधित करते समय पुनरावृत्ति अपरिभाषित व्यवहार की ओर ले जाती है - यह अन्य भाषाओं में भी मान्य है। यहां मात्ज़ का जवाब है (वह एक ऐरे का उपयोग करके एक उदाहरण का जवाब देता है, लेकिन इसका उत्तर सामान्य है): j.mp/tPOh2U
मार्कस

4
@ मेरकस मैं मानता हूं कि सामान्य तौर पर ऐसे संशोधन से बचना चाहिए। लेकिन इस मामले में यह शायद सुरक्षित है, क्योंकि संशोधन भविष्य के पुनरावृत्तियों को नहीं बदलता है। अब अगर कोई दूसरी कुंजी (जो ब्लॉक में पास नहीं हुई थी) को सौंपा गया था, तो परेशानी होगी।
केल्विन

36
जब आप हैश के साथ ब्लॉक समाप्त नहीं करना चाहते तो @Adam @kch each_with_objectएक अधिक सुविधाजनक संस्करण है inject:my_hash.each_with_object({}) {|(k, v), h| h[k] = v.upcase }
केल्विन

6
जोड़े की सूची को हैश में बदलने के लिए एक बहुत साफ वाक्यविन्यास भी है, इसलिए आप लिख सकते हैंa_new_hash = Hash[ my_hash.map { |k, v| [k, v.upcase] } ]
फिर से लिखना

2
रूबी 2 के साथ आप लिख सकते हैं.to_h
रोमन-रोमन

101

चूंकि 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!संस्करण भी है ।


5
महान है, यह भी रेल 4.2.1 के साथ आता है apidock.com/rails/v4.2.1/Hash/transform_values
कोडा चांग

35

आप मान एकत्र कर सकते हैं, और इसे फिर से ऐश से हश में परिवर्तित कर सकते हैं।

ऐशे ही:

config = Hash[ config.collect {|k,v| [k, v.upcase] } ]

23

यह यह करेगा:

my_hash.each_with_object({}) { |(key, value), hash| hash[key] = value.upcase }

जैसा injectकि लाभ के विपरीत है कि आपको ब्लॉक के अंदर फिर से हैश वापस करने की कोई आवश्यकता नहीं है।


मुझे यह पसंद है कि यह विधि मूल हैश को संशोधित नहीं करती है।
क्रिश्चियन डि लोरेंजो

10

इस फ़ंक्शन का प्रयास करें:

h = {"a" => "b", "c" => "d"}
h.each{|i,j| j.upcase!} # now contains {"a" => "B", "c" => "D"}.

5
यह अच्छा है, लेकिन यह ध्यान दिया जाना चाहिए कि यह केवल तब काम करता है जब जम्मू में एक विध्वंसक विधि होती है जो स्वयं के लिए कार्य करती है। तो यह सामान्य value.some_method मामले को संभाल नहीं सकता है।
kch

अच्छा बिंदु, और उसके अद्यतन के साथ, आपका दूसरा समाधान (गैर-विनाशकारी) सबसे अच्छा है।
क्रिस डोगेट

10

ActiveSupport v4.2.0 में इसके लिए एक विधि है । यह कहा जाता है transform_valuesऔर मूल रूप से प्रत्येक कुंजी-मूल्य-जोड़ी के लिए बस एक ब्लॉक निष्पादित करता है।

जब से वे ऐसा कर रहे हैं eachमुझे लगता है कि वहाँ से बेहतर कोई रास्ता नहीं है के माध्यम से पाश।

hash = {sample: 'gach'}

result = {}
hash.each do |key, value|
  result[key] = do_stuff(value)
end

अपडेट करें:

रूबी 2.4.0 के बाद से आप मूल रूप से उपयोग कर सकते हैं #transform_valuesऔर #transform_values!


2

आप एक कदम और आगे बढ़ सकते हैं और एक नेस्टेड हैश पर ऐसा कर सकते हैं। निश्चित रूप से यह रेल परियोजनाओं के साथ एक उचित राशि है।

यहाँ कुछ कोड सुनिश्चित करने के लिए हैशटैग 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  

1

मैं ऐसा कुछ करता हूं:

new_hash = हैश [* original_hash.collect {| कुंजी, मूल्य | [कुंजी, मान + 1]}

यह आपको किसी भी अभिव्यक्ति के माध्यम से कुंजी या मूल्य को बदलने की सुविधा प्रदान करता है (और यह गैर-विनाशकारी है, निश्चित रूप से)।


1

रूबी में tapविधि ( 1.8.7 , 1.9.3 और 2.1.0 ) है जो इस तरह से सामान के लिए बहुत उपयोगी है।

original_hash = { :a => 'a', :b => 'b' }
original_hash.clone.tap{ |h| h.each{ |k,v| h[k] = v.upcase } }
# => {:a=>"A", :b=>"B"}
original_hash # => {:a=>"a", :b=>"b"}

1

रेल विशेष

यदि किसी को केवल to_sमूल्यों में से प्रत्येक के लिए विधि को कॉल करने की आवश्यकता होती है और वह रेल्स 4.2 का उपयोग नहीं कर रहा है (जिसमें transform_valuesविधि लिंक शामिल है ), तो आप निम्नलिखित कर सकते हैं:

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: यह चाबी को तार में बदल देगा


1

यदि आप जानते हैं कि मूल्य स्ट्रिंग हैं, तो आप चक्र में रहते हुए उन पर प्रतिस्थापित विधि को कॉल कर सकते हैं: इस तरह आप मूल्य बदल देंगे।

Altohugh यह उस मामले तक सीमित है जिसमें मान तार हैं और इसलिए पूरी तरह से सवाल का जवाब नहीं देता है, मैंने सोचा कि यह किसी के लिए उपयोगी हो सकता है।


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

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