Bir değerdeki her değeri, değerden önce ve sonra '%' eklemek için değiştirmek istiyorum
{ :a=>'a' , :b=>'b' }
olarak değiştirilmeli
{ :a=>'%a%' , :b=>'%b%' }
Bunu yapmanın en iyi yolu nedir?
Bir değerdeki her değeri, değerden önce ve sonra '%' eklemek için değiştirmek istiyorum
{ :a=>'a' , :b=>'b' }
olarak değiştirilmeli
{ :a=>'%a%' , :b=>'%b%' }
Bunu yapmanın en iyi yolu nedir?
Yanıtlar:
Gerçek dizelerin kendilerinin yerinde değişmesini istiyorsanız (muhtemelen ve istenen şekilde aynı dize nesnelerine yapılan diğer başvuruları etkiler):
# Two ways to achieve the same result (any Ruby version)
my_hash.each{ |_,str| str.gsub! /^|$/, '%' }
my_hash.each{ |_,str| str.replace "%#{str}%" }
Karma'nın yerinde değişmesini istiyorsanız, ancak dizeleri etkilemek istemiyorsanız (yeni dizeler almasını istiyorsanız):
# 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 }
Yeni bir karma istiyorsanız:
# 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}%"] } ]
Hash.[]
bir dizi dizi çiftini kabul etmez , çift sayıda doğrudan argüman gerektirir (bu nedenle önden uyarı).
Hash#each
hem anahtar hem de değer verir. Bu durumda, anahtarı umursamadım ve bu yüzden yararlı bir şey söylemedim. Değişken isimleri bir alt çizgi ile başlayabilir ve aslında sadece bir alt çizgi olabilir. Bunu yapmanın hiçbir performans avantajı yok, bu ilk blok değeri ile hiçbir şey yapmıyorum sadece kendini belgeleyen ince bir not.
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
, hash bloktan geri dönmek zorunda
Ruby 2.1 ve üstü sürümlerde şunları yapabilirsiniz:
{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
#transform_values!
2.4+ kullanıyorsanız , sschmeck ( stackoverflow.com/a/41508214/6451879 ) tarafından belirtildiği gibi kullanmak daha da kolaydır .
Ruby 2.4 Hash#transform_values!
kullanabileceğiniz yöntemi tanıttı .
{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"}
Hash#transform_values
alıcıyı değiştirmeyen (patlama olmadan) da var. Aksi takdirde harika bir cevap, teşekkürler!
Bir Hash'in değerlerini yerinde değiştirmenin en iyi yolu
hash.update(hash){ |_,v| "%#{v}%" }
Daha az kod ve açık niyet. Ayrıca, değiştirilmesi gereken değerlerin ötesinde hiçbir yeni nesne tahsis edilmediğinden daha hızlıdır.
gsub!
.
update
niyeti daha iyi ilettiğini kabul ediyorum merge!
. Bence bu en iyi cevap.
k
, kullanmak _
yerine.
A, daha okunabilir bir bit map
bu tek öğeli karma bir dizi ve reduce
omerge
the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Hash[the_hash.map { |key,value| [key, "%#{value}%"] }]
Array
(for map
) sonra a oluşturur Hash
. Daha sonra, azaltma işleminin her adımı "not" u çoğaltacak Hash
ve yeni anahtar / değer çiftini buna ekleyecektir. En kullanımda az :merge!
yer reduce
nihai değiştirmek için Hash
yerinde. Ve sonunda, mevcut nesnenin değerlerini değiştirmiyorsunuz, ancak sorunun sorduğu yeni bir nesne oluşturuyorsunuz.
nil
eğer the_hash
boş
Bu görev için yeni bir 'Raylar yolu' yöntemi var :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values
Hash#transform_values
. Bundan böyle devam etmeli.
Orijinaline yan etkiler getirmeyen bir yöntem:
h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
Hash # haritası ayrıca Hash.map
bir Hash döndürmediğini açıklayan ilginç bir okuma olabilir (bu nedenle sonuçta ortaya çıkan [key,value]
çiftler dizisi yeni bir Hash'e dönüştürülür) ve aynı genel desene alternatif yaklaşımlar sağlar.
Mutlu kodlama.
[Feragatname: Hash.map
Ruby 2.x'te anlambilimin değişip değişmediğinden emin değilim ]
Hash.map
, Ruby 2.x'te anlambilimin değişip değişmediğini bile biliyor mu?
my_hash.each do |key, value|
my_hash[key] = "%#{value}%"
end
each_with_object
Yakında 1.9 (IIRC) var, bu da isme doğrudan erişmeye gerek kalmıyor ve Map#merge
aynı zamanda işe yarayabilir. Karmaşık ayrıntıların nasıl farklı olduğundan emin değilim.
Bunun gibi RSpec ile test ettikten sonra:
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
Hash # map_values uygulamasını aşağıdaki gibi uygulayabilirsiniz:
class Hash
def map_values
Hash[map { |k, v| [k, yield(v)] }]
end
end
Fonksiyon daha sonra şu şekilde kullanılabilir:
{:a=>'a' , :b=>'b'}.map_values { |v| "%#{v}%" }
# {:a=>"%a%", :b=>"%b%"}
Hangi en hızlı varyantın burada en hızlı olduğunu merak ediyorsanız:
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