रूबी में एक हैश में हर मूल्य को बदलना


170

मैं एक हैश में हर मूल्य को बदलना चाहता हूं ताकि मूल्य से पहले और बाद में '%' को जोड़ा जा सके

{ :a=>'a' , :b=>'b' }

को बदलना होगा

{ :a=>'%a%' , :b=>'%b%' }

ऐसा करने का सबसे अच्छा तरीका क्या है?


1
कृपया स्पष्ट करें कि क्या आप मूल स्ट्रिंग ऑब्जेक्ट्स को म्यूट करना चाहते हैं, बस मूल को म्यूट करें, या कुछ भी म्यूट न करें।
फ्रॉग्ज

1
तब आपने गलत उत्तर को स्वीकार कर लिया है। (@Pst के लिए कोई अपराध नहीं है, जैसा कि मैं व्यक्तिगत रूप से वस्तुओं को बदलने के बजाय कार्यात्मक शैली प्रोग्रामिंग की वकालत करता हूं।)
फ्रॉग्ज

लेकिन फिर भी दृष्टिकोण अच्छा था
RRerseFlick

जवाबों:


178

यदि आप चाहते हैं कि वास्तविक स्ट्रिंग्स स्वयं स्थान पर उत्परिवर्तित करें (संभवतः और समान रूप से उसी स्ट्रिंग ऑब्जेक्ट के अन्य संदर्भों को प्रभावित कर रहे हैं):

# 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}%"] } ]

1
@ और मार्शल मार्शल आप सही हैं, धन्यवाद। रूबी 1.8 में, Hash.[]सरणी जोड़े की एक श्रृंखला को स्वीकार नहीं करता है, इसके लिए प्रत्यक्ष तर्क की एक समान संख्या की आवश्यकता होती है (इसलिए सामने की तरफ)।
फ्रॉग्ज

2
दरअसल, हैश। [Key_value_pairs] को 1.8.7 में पेश किया गया था, इसलिए केवल रूबी 1.8.6 को स्पैट एंड फ्लैटन की आवश्यकता नहीं है।
मार्क-आंद्रे लैफट्यून

2
@Aupajo Hash#eachब्लॉक की कुंजी और मान दोनों देता है। इस मामले में, मुझे चाबी की परवाह नहीं थी, और इसलिए मैंने इसे कुछ भी उपयोगी नहीं बताया। परिवर्तनीय नाम एक अंडरस्कोर के साथ शुरू हो सकते हैं, और वास्तव में सिर्फ एक अंडरस्कोर हो सकते हैं । ऐसा करने का कोई प्रदर्शन लाभ नहीं है, यह सिर्फ एक सूक्ष्म स्व-दस्तावेज नोट है जो मैं उस पहले ब्लॉक मूल्य के साथ कुछ नहीं कर रहा हूं।
फ़रोज़

1
मुझे लगता है कि आपका मतलब है my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }, ब्लॉक से हैश लौटना है
aceofspades

1
वैकल्पिक रूप से, आप प्रत्येक_वायु पद्धति का उपयोग कर सकते हैं, जो अप्रयुक्त कुंजी मूल्य के लिए अंडरस्कोर का उपयोग करने की तुलना में समझना थोड़ा आसान है।
स्ट्रैंड मेककचेन

266

रूबी 2.1 और उच्चतर में आप कर सकते हैं

{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h

5
धन्यवाद, वास्तव में मैं क्या देख रहा था। पता नहीं क्यों तुम इतना ऊपर नहीं कर रहे हैं।
सिम्प्रेरेल्ट

7
यह, हालांकि, बहुत धीमी है और बहुत रैम भूख लगी है। इनपुट हैश को नेस्टेड एरेज़ के एक मध्यवर्ती सेट का उत्पादन करने के लिए पुनरावृत्त किया जाता है जिसे बाद में एक नए हैश में बदल दिया जाता है। रैम पीक के उपयोग को नजरअंदाज करते हुए, रन टाइम बहुत खराब होता है - इसे एक अन्य उत्तर शो में संशोधित संशोधित इन-प्लेस समाधान 2.5 s बनाम 1.5s पुनरावृत्तियों के समान संख्या में दिखाता है। चूँकि रूबी एक तुलनात्मक रूप से धीमी भाषा है, इसलिए धीमी भाषा से
एंड्रयू होडकिंसन

2
@AndrewHodgkinson सामान्य रूप से सहमत हूं और मैं रनटाइम प्रदर्शन पर ध्यान नहीं देने की वकालत कर रहा हूं, क्या इन सभी प्रदर्शनों पर नज़र नहीं रखने से दर्द होना शुरू हो जाता है और माणिक के "डेवलपर उत्पादकता पहले" दर्शन के खिलाफ जाना है? मुझे लगता है कि यह आपके लिए एक टिप्पणी से कम नहीं है, और अंत में रूबी का उपयोग करते हुए हमें इस पर विरोधाभास की एक सामान्य टिप्पणी के बारे में अधिक जानकारी मिलती है।
1917 को elsurudo

4
यह समझदारी है: ठीक है, हम पहले से ही रूबी का उपयोग करने के लिए अपने निर्णय में प्रदर्शन दे रहे हैं, इसलिए इससे क्या फर्क पड़ता है? यह एक फिसलन ढलान है, यह नहीं है? रिकॉर्ड के लिए, मैं इस समाधान को एक पठनीयता के दृष्टिकोण से, स्वीकृत उत्तर के लिए पसंद करता हूं।
एल्सरुडो

1
यदि आप रूबी #transform_values!2.4+ का उपयोग करते हैं, तो sschmeck ( stackoverflow.com/a/41508214/6451879 ) द्वारा बताया गया उपयोग करना और भी आसान है ।
फिन

127

रूबी 2.4 ने विधि पेश की Hash#transform_values!, जिसका आप उपयोग कर सकते हैं।

{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"} 

ठीक वही जो मेरे द्वारा खोजा जा रहा था!
Dolev

4
बेशक Hash#transform_values(धमाके के बिना) भी है, जो रिसीवर को संशोधित नहीं करता है। अन्यथा एक महान जवाब, धन्यवाद!
आईजीईएल

1
यह वास्तव में मेरे उपयोग को कम करेगा reduce:
-पी

86

हश के मूल्यों को संशोधित करने का सबसे अच्छा तरीका है

hash.update(hash){ |_,v| "%#{v}%" }

कम कोड और स्पष्ट इरादा। तेजी से भी क्योंकि कोई भी नई वस्तुओं को उन मूल्यों से परे आवंटित नहीं किया जाता है जिन्हें बदलना होगा।


बिल्कुल सही नहीं: नए तार आवंटित किए गए हैं। फिर भी, एक दिलचस्प समाधान जो प्रभावी है। +1
फ़रोज़

@ फ्रॉग अच्छी बात; मैंने जवाब अपडेट किया। मूल्य आबंटन को सामान्य रूप से टाला नहीं जा सकता क्योंकि सभी मूल्य परिवर्तन को म्यूटेटर के रूप में व्यक्त नहीं किया जा सकता है gsub!
Sim

3
मेरे उत्तर के समान लेकिन एक और पर्यायवाची के साथ, मैं सहमत हूं कि updateइस इरादे से बेहतर है merge!। मुझे लगता है कि यह सबसे अच्छा जवाब है।

1
यदि आप उपयोग नहीं करते हैं k, तो _इसके बजाय उपयोग करें ।
सेक्रेट

28

एक और अधिक पठनीय एक, mapयह एकल-तत्व हैश की एक सरणी के reduceसाथ और वह हैmerge

the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)

2
स्पष्ट उपयोग करने के लिएHash[the_hash.map { |key,value| [key, "%#{value}%"] }]
meagar

मूल्यों को अपडेट करने का यह एक बेहद अक्षम तरीका है। प्रत्येक मूल्य जोड़ी के लिए यह पहले एक जोड़ी बनाता है Array(के लिए map) फिर ए Hash। फिर, कम किए गए ऑपरेशन के प्रत्येक चरण "मेमो" की नकल करेंगे Hashऔर इसमें नए कुंजी-मूल्य जोड़े को जोड़ेंगे। कम से कम उपयोग पर :merge!में reduceअंतिम संशोधित करने के लिए Hashजगह में। और अंत में, आप मौजूदा ऑब्जेक्ट के मूल्यों को संशोधित नहीं कर रहे हैं, बल्कि एक नई वस्तु का निर्माण कर रहे हैं, जो कि सवाल नहीं पूछा गया है।
सिम

यह रिटर्न nilयदि the_hashरिक्त है
DNNX

18

इस कार्य के लिए एक नया 'रेल मार्ग' है :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values


8
इसके अलावा रूबी 2.4.0+ में है Hash#transform_values। यह अब से जाने का रास्ता होना चाहिए।
ambebe

1
संक्षेप में, रेल 5+ या रूबी
2.4+ के


16

एक तरीका जो मूल-प्रभाव का परिचय नहीं देता है:

h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]

हैश # मैप भी एक दिलचस्प रीड हो सकता है क्योंकि यह बताता है कि Hash.mapहैश क्यों नहीं लौटता (यही कारण है कि [key,value]जोड़े का परिणामी सरणी एक नए हैश में परिवर्तित हो जाता है) और उसी सामान्य पैटर्न के लिए वैकल्पिक दृष्टिकोण प्रदान करता है।

खुश कोडिंग।

[अस्वीकरण: मुझे यकीन नहीं है कि अगर Hash.mapशब्दार्थ रूबी २.x में बदल जाए]


7
क्या मात्ज़ को भी पता है कि क्या Hash.mapशब्दार्थ रूबी 2.x में बदल जाता है?
एंड्रयू ग्रिम

1
हैश # [] विधि इतनी उपयोगी है, लेकिन इतनी बदसूरत है। क्या उसी तरीके से ऐश को हैश में परिवर्तित करने का एक प्रचलित तरीका है?
मार्टिज़न

15
my_hash.each do |key, value|
  my_hash[key] = "%#{value}%"
end

मुझे साइड-इफेक्ट्स पसंद नहीं हैं, लेकिन एप्रोच के लिए +1 :) each_with_objectरूबी 1.9 (आईआईआरसी) में है जो सीधे नाम तक पहुंचने की आवश्यकता से बचता है और Map#mergeकाम भी कर सकता है। सुनिश्चित नहीं है कि जटिल विवरण कैसे भिन्न हैं।

1
प्रारंभिक हैश को संशोधित किया गया है - यह ठीक है अगर व्यवहार अनुमानित है लेकिन "भूल" जाने पर सूक्ष्म मुद्दों का कारण बन सकता है। मैं ऑब्जेक्ट उत्परिवर्तन को कम करना पसंद करता हूं, लेकिन यह हमेशा व्यावहारिक नहीं हो सकता है। (रूबी मुश्किल से एक "साइड-इफ़ेक्ट-फ्री" भाषा; ;-)

8

Hash.merge! सबसे साफ समाधान है

o = { a: 'a', b: 'b' }
o.merge!(o) { |key, value| "%#{ value }%" }

puts o.inspect
> { :a => "%a%", :b => "%b%" }

@MichieldeMare मुझे क्षमा करें, मैंने इसे पूरी तरह से परीक्षण नहीं किया है। आप सही हैं, ब्लॉक को दो पैरामीटर लेने की जरूरत है। सही किया।

5

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

आप हश # 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%"}

1

यदि आप जिज्ञासु हैं कि कौन सा विस्थापित संस्करण सबसे तेज़ है तो यह है:

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.