web-dev-qa-db-de.com

Ändern Sie jeden Wert in einem Hash in Ruby

Ich möchte jeden Wert in einem Hash ändern, um '%' vor und nach dem Wert hinzuzufügen

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

muss geändert werden zu

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

Wie geht das am besten?

153
theReverseFlick

Wenn Sie möchten, dass die tatsächlichen Zeichenfolgen selbst an der richtigen Stelle mutieren (möglicherweise und wünschenswerterweise Auswirkungen auf andere Verweise auf dieselben Zeichenfolgenobjekte):

# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }

Wenn Sie möchten, dass sich der Hash ändert, die Zeichenfolgen jedoch nicht beeinflusst werden sollen (Sie möchten, dass neue Zeichenfolgen abgerufen werden):

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

Wenn Sie einen neuen Hash wollen:

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

In Ruby 2.1 und höher ist dies möglich

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

Ruby 2.4 hat die Methode Hash#transform_values! , welches du benutzen könntest.

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

Die beste Möglichkeit, die Werte eines Hashs zu ändern, ist

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

Weniger Code und klare Absichten. Auch schneller, weil über die zu ändernden Werte hinaus keine neuen Objekte zugewiesen werden.

80
Sim

Ein bisschen lesbarer, map es zu einem Array von Einzelelement-Hashes und reduce das mit merge

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

Für diese Aufgabe gibt es eine neue Rails-Methode :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values

17
woto

Eine Methode, die dem Original keine Nebenwirkungen verleiht:

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

Hash # map kann auch eine interessante Lektüre sein, da es erklärt, warum das Hash.map gibt keinen Hash zurück (weshalb das resultierende Array von [key,value] pairs wird in einen neuen Hash umgewandelt) und bietet alternative Ansätze für dasselbe allgemeine Muster.

Fröhliches Codieren.

[Haftungsausschluss: Ich bin nicht sicher, ob Hash.map Semantikänderung in Ruby 2.x]

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

Hash.merge! Ist die sauberste Lösung

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

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

Nach dem Testen mit RSpec wie folgt:

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

Sie können Hash # map_values ​​wie folgt implementieren:

class Hash
  def map_values
    Hash[map { |k, v| [k, yield(v)] }]
  end
end

Die Funktion kann dann folgendermaßen verwendet werden:

{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}
5
wedesoft