ฉันต้องการเปลี่ยนค่าทุกค่าในแฮชเพื่อเพิ่ม '%' ก่อนและหลังค่า
{ :a=>'a' , :b=>'b' }
จะต้องเปลี่ยนเป็น
{ :a=>'%a%' , :b=>'%b%' }
วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?
ฉันต้องการเปลี่ยนค่าทุกค่าในแฮชเพื่อเพิ่ม '%' ก่อนและหลังค่า
{ :a=>'a' , :b=>'b' }
จะต้องเปลี่ยนเป็น
{ :a=>'%a%' , :b=>'%b%' }
วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?
คำตอบ:
หากคุณต้องการให้สตริงที่แท้จริงกลายพันธุ์เอง (อาจเป็นไปได้และน่าปรารถนาที่จะส่งผลกระทบต่อการอ้างอิงอื่น ๆ ไปยังวัตถุสตริงเดียวกัน):
# 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}%"] } ]
Hash.[]
ไม่ยอมรับอาร์เรย์ของคู่ของอาเรย์มันต้องมีการโต้แย้งโดยตรงจำนวนคู่
Hash#each
ให้ทั้งคีย์และค่าของบล็อก ในกรณีนี้ฉันไม่สนใจเกี่ยวกับกุญแจดังนั้นฉันจึงไม่ได้ตั้งชื่อสิ่งที่มีประโยชน์ ชื่อตัวแปรอาจเริ่มต้นด้วยการขีดเส้นใต้และอันที่จริงอาจเป็นเพียงการขีดเส้นใต้ ไม่มีประโยชน์ด้านประสิทธิภาพในการทำสิ่งนี้มันเป็นเพียงแค่การบันทึกเอกสารด้วยตนเองที่ละเอียดอ่อนว่าฉันไม่ได้ทำอะไรกับค่าบล็อกแรก
my_hash.inject(my_hash){ |h,(k,str)| h[k]="%#{str}%"; h }
ต้องคืนแฮชจาก block
ใน Ruby 2.1 ขึ้นไปคุณสามารถทำได้
{ a: 'a', b: 'b' }.map { |k, str| [k, "%#{str}%"] }.to_h
#transform_values!
ตามที่ระบุไว้โดย sschmeck ( stackoverflow.com/a/41508214/6451879 )
Ruby 2.4 แนะนำวิธีการHash#transform_values!
ที่คุณสามารถใช้ได้
{ :a=>'a' , :b=>'b' }.transform_values! { |v| "%#{v}%" }
# => {:a=>"%a%", :b=>"%b%"}
Hash#transform_values
(ไม่มีปัง) ซึ่งไม่ได้ปรับเปลี่ยนผู้รับ มิฉะนั้นคำตอบที่ดีขอบคุณ!
วิธีที่ดีที่สุดในการปรับเปลี่ยนค่าของแฮชคือ
hash.update(hash){ |_,v| "%#{v}%" }
รหัสน้อยลงและความตั้งใจที่ชัดเจน เร็วกว่าเนื่องจากไม่มีการจัดสรรวัตถุใหม่นอกเหนือจากค่าที่ต้องเปลี่ยน
gsub!
เช่น
update
merge!
ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุด
k
ให้ใช้_
แทน
บิตที่อ่านได้มากขึ้นmap
ไปยังอาร์เรย์ของแฮชองค์ประกอบเดี่ยวและreduce
ด้วยmerge
the_hash.map{ |key,value| {key => "%#{value}%"} }.reduce(:merge)
Hash[the_hash.map { |key,value| [key, "%#{value}%"] }]
Array
(สำหรับmap
) Hash
แล้ว จากนั้นแต่ละขั้นตอนของการดำเนินการลดจะทำซ้ำ "บันทึก" Hash
และเพิ่มคู่คีย์ - ค่าใหม่ลงไป อย่างน้อยใช้:merge!
ในreduce
การปรับเปลี่ยนสุดท้ายHash
ในสถานที่ และในที่สุดคุณไม่ได้แก้ไขค่าของวัตถุที่มีอยู่ แต่สร้างวัตถุใหม่ซึ่งไม่ใช่สิ่งที่คำถามถาม
nil
ถ้าthe_hash
ว่างเปล่า
มีวิธีการ 'Rails way' ใหม่สำหรับงานนี้ :) http://api.rubyonrails.org/classes/Hash.html#method-i-transform_values
Hash#transform_values
นอกจากนี้ยังมีทับทิม 2.4.0+ นี่ควรเป็นวิธีที่จะดำเนินการต่อจากนี้ไป
วิธีการหนึ่งที่ไม่แนะนำให้เกิดผลข้างเคียงกับต้นฉบับ:
h = {:a => 'a', :b => 'b'}
h2 = Hash[h.map {|k,v| [k, '%' + v + '%']}]
แผนที่ Hash #อาจเป็นสิ่งที่น่าสนใจในการอ่านเนื่องจากอธิบายว่าทำไมHash.map
ไม่ส่งคืน Hash (ซึ่งเป็นสาเหตุที่ Array ของ[key,value]
คู่ผลลัพธ์ถูกแปลงเป็น Hash ใหม่) และให้แนวทางอื่นในรูปแบบทั่วไปแบบเดียวกัน
การเข้ารหัสที่มีความสุข
[คำเตือน: ฉันไม่แน่ใจว่าซีแมนทิกส์Hash.map
เปลี่ยนเป็น Ruby 2.x]
Hash.map
ติกส์เปลี่ยนใน Ruby 2.x หรือไม่?
my_hash.each do |key, value|
my_hash[key] = "%#{value}%"
end
each_with_object
ใน Ruby 1.9 (IIRC) ซึ่งหลีกเลี่ยงการจำเป็นต้องเข้าถึงชื่อโดยตรงและMap#merge
อาจใช้งานได้ ไม่แน่ใจว่ารายละเอียดที่ซับซ้อนแตกต่างกันอย่างไร
Hash.merge! เป็นทางออกที่สะอาดที่สุด
o = { a: 'a', b: 'b' }
o.merge!(o) { |key, value| "%#{ value }%" }
puts o.inspect
> { :a => "%a%", :b => "%b%" }
หลังจากทดสอบด้วย 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
คุณสามารถใช้ Hash # 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%"}
หากคุณอยากรู้ว่าตัวแปรแบบไหนที่เร็วที่สุดที่นี่:
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