เมื่อแปลความคิดของคุณเป็นโค้ด เป็นไปได้มากว่าคุณจะใช้วิธีที่คุณคุ้นเคยมากที่สุด นี่คือวิธีการที่สำคัญที่สุดและมาถึงคุณโดยอัตโนมัติ:คุณเห็นสตริงที่ต้องการทำความสะอาดและนิ้วของคุณพิมพ์วิธีการที่จะได้ผลลัพธ์
บ่อยครั้งที่วิธีการที่คุณพิมพ์โดยอัตโนมัติเป็นวิธี Ruby ทั่วไปมากที่สุด เนื่องจากเป็นวิธีที่เราอ่านและเขียนมากกว่าวิธีอื่นๆ เช่น #gsub
เป็นวิธีการทั่วไปในการแทนที่อักขระในสตริง แต่ Ruby มีอะไรอีกมากมายที่จะนำเสนอ พร้อมด้วยวิธีการอำนวยความสะดวกเฉพาะทางสำหรับการปฏิบัติงานมาตรฐาน
ฉันชอบสำนวนที่เข้มข้นของ Ruby ส่วนใหญ่เพราะมันทำให้โค้ดดูหรูหราและอ่านง่ายขึ้น หากเราต้องการได้รับประโยชน์จากความสมบูรณ์นี้ เราต้องใช้เวลาในการจัดโครงสร้างใหม่แม้กระทั่งส่วนที่ง่ายที่สุดของโค้ดของเรา เช่น การล้างสตริง และใช้ความพยายามเล็กน้อยในการขยายคำศัพท์ของเรา คำถามคือ ความพยายามพิเศษคุ้มค่าหรือไม่
สี่วิธีในการลบ Spaces
นี่คือสตริงที่แสดงถึงหมายเลขบัตรเครดิต:"055 444 285" ในการทำงานกับมัน เราต้องการลบช่องว่าง #gsub
สามารถทำได้; ด้วย #gsub
คุณสามารถแทนที่อะไรก็ได้กับทุกอย่าง แต่มีตัวเลือกอื่น
string = "055 444 285"
string.gsub(/ /, '')
string.gsub(' ', '')
string.tr(' ', '')
string.delete(' ')
# => "055444285"
เป็นการแสดงออกที่ฉันชอบมากที่สุดเกี่ยวกับวิธีการอำนวยความสะดวก อันสุดท้ายเป็นตัวอย่างที่ดีของสิ่งนี้:ไม่ได้ชัดเจนไปกว่า "การลบช่องว่าง" เมื่อนึกถึงการประนีประนอมระหว่างตัวเลือกต่างๆ ความสามารถในการอ่านเป็นสิ่งสำคัญอันดับแรกของฉัน เว้นแต่แน่นอนว่าจะทำให้เกิดปัญหาด้านประสิทธิภาพ มาดูกันดีกว่าว่าวิธีแก้ปัญหาที่ฉันโปรดปราน #delete
สาเหตุจริงๆ
ฉันเปรียบเทียบตัวอย่างข้างต้น คุณคิดว่าวิธีใดเร็วที่สุด
Benchmark.ips do |x|
x.config(time: 30, warmup: 2)
x.report('gsub') { string.gsub(/ /, '') }
x.report('gsub, no regex') { string.gsub(' ', '') }
x.report('tr') { string.tr(' ','') }
x.report('delete') { string.delete(' ') }
x.compare!
end
เดาลำดับจากมากไปน้อย เปิดสวิตช์เพื่อดูผลลัพธ์
Comparison:
delete: 2326817.5 i/s
tr: 2121629.8 i/s - 1.10x slower
gsub, no regex: 868184.1 i/s - 2.68x slower
gsub: 474970.5 i/s - 4.90x slower
ฉันไม่แปลกใจกับการสั่งซื้อ แต่ความแตกต่างของความเร็วยังคงทำให้ฉันประหลาดใจ #gsub
ไม่เพียงแต่ช้าลงเท่านั้น แต่ยังต้องใช้ความพยายามเป็นพิเศษสำหรับผู้อ่านในการ 'ถอดรหัส' อาร์กิวเมนต์ มาดูกันว่าการเปรียบเทียบนี้จะออกมาเป็นอย่างไรเมื่อต้องทำความสะอาดมากกว่าแค่ช่องว่าง
เลือกหมายเลขของคุณ
ใช้หมายเลขโทรศัพท์ต่อไปนี้:'(408) 974-2414'
. สมมติว่าเราต้องการแค่ตัวเลข => 4089742414
. ฉันเพิ่ม #scan
เช่นกัน เพราะฉันชอบที่มันแสดงออกอย่างชัดเจนว่าเราตั้งเป้าหมายบางอย่าง แทนที่จะพยายามลบสิ่งที่เราไม่ต้องการออกไป
Benchmark.ips do |x|
x.config(time: 30, warmup: 2)
x.report ('gsub') { string.gsub(/[^0-9] /, '') }
x.report('tr') { string.tr("^0-9", "") }
x.report('delete_chars') { string.delete("^0-9") }
x.report('scan') { string.scan(/[0-9]/).join }
x.compare!
end
อีกครั้ง เดาลำดับ จากนั้นเปิดสวิตช์เพื่อดูคำตอบ
Comparison:
delete_chars: 2006750.8 i/s
tr: 1856429.0 i/s - 1.08x slower
gsub: 523174.7 i/s - 3.84x slower
scan: 227717.4 i/s - 8.81x slower
การใช้ regex ทำให้สิ่งต่างๆ ช้าลง ไม่น่าแปลกใจเลย และความตั้งใจเผยความชัดเจนของ #scan
ค่าใช้จ่ายเราอย่างสุดซึ้ง แต่เมื่อดูวิธีที่ Ruby เชี่ยวชาญในการทำความสะอาด ทำให้ฉันได้ลิ้มลองมากขึ้น
เรื่องเงิน
ลองใช้วิธีลบสตริงย่อย "€ "
จากสตริง "€ 300"
. โซลูชันบางส่วนต่อไปนี้ระบุสตริงย่อยที่แน่นอน "€ "
บางส่วนจะลบสัญลักษณ์สกุลเงินทั้งหมดหรืออักขระที่ไม่ใช่ตัวเลขทั้งหมดออก
Benchmark.ips do |x|
x.config(time: 30, warmup: 2)
x.report('delete specific chars') { string.delete("€ ") }
x.report('delete non-numericals') { string.delete("^0-9") }
x.report('delete prefix') { string.delete_prefix("€ ") }
x.report('delete prefix, strip') { string.delete_prefix("€").strip }
x.report('gsub') { string.gsub(/€ /, '') }
x.report('gsub-non-nums') { string.gsub(/[^0-9]/, '') }
x.report('tr') { string.tr("€ ", "") }
x.report('slice array') { string.chars.slice(2..-1).join }
x.report('split') { string.split.last }
x.report('scan nums') { string.scan(/\d/).join }
x.compare!
end
คุณอาจคาดหวังและถูกต้องว่าผู้ชนะคือหนึ่งใน #delete
ส. แต่อันไหนใน #delete
ตัวแปรที่คุณคาดว่าจะเร็วที่สุด? บวก:วิธีอื่นเร็วกว่าวิธี #delete
ส. อันไหน?
เดาแล้วเปิดเลย
Comparison:
delete prefix: 4236218.6 i/s
delete prefix, strip: 3116439.6 i/s - 1.36x slower
split: 2139602.2 i/s - 1.98x slower
delete non-numericals: 1949754.0 i/s - 2.17x slower
delete specific chars: 1045651.9 i/s - 4.05x slower
tr: 951352.0 i/s - 4.45x slower
slice array: 681196.2 i/s - 6.22x slower
gsub: 548588.3 i/s - 7.72x slower
gsub-non-nums: 489744.8 i/s - 8.65x slower
scan nums: 418978.8 i/s - 10.11x slower
ฉันรู้สึกประหลาดใจที่แม้แต่การแบ่งอาร์เรย์ก็เร็วกว่า #gsub
และฉันยินดีเสมอที่ได้เห็น #split
. เร็วแค่ไหน เป็น. และโปรดทราบว่าการลบที่ไม่ใช่ตัวเลขทั้งหมดนั้นเร็วกว่าการลบสตริงย่อยที่ระบุ
ติดตามเงิน
มาลบสกุลเงินหลังตัวเลขกัน (ฉันข้าม #gsub
. ที่ช้ากว่า แบบต่างๆ)
Benchmark.ips do |x|
x.config(time: 30, warmup: 2)
x.report('gsub') { string.gsub(/ USD/, '')
x.report('tr') { string.tr(" USD", "") }
x.report('delete_chars') { string.delete("^0-9")
x.report('delete_suffix') { string.delete_suffix(" USD") }
x.report('to_i.to_s') { string.to_i.to_s }
x.report("split") { string.split.first }
x.compare!
end
มีการเสมอกันระหว่างผู้ชนะ 2 ตัวไหนที่คุณคาดหวังว่าจะแข่งกันให้เร็วที่สุด
และ:เดาว่า `#gsub' ช้ากว่า `#gsub` แค่ไหน'
Comparison:
delete_suffix: 4354205.4 i/s
to_i.to_s: 4307614.6 i/s - same-ish: difference falls within error
split: 2870187.8 i/s - 1.52x slower
delete_chars: 1989566.1 i/s - 2.19x slower
tr: 1853957.1 i/s - 2.35x slower
gsub: 524080.6 i/s - 13.22x slower
ไม่มีวิธีการเฉพาะที่เหมาะกับความต้องการของคุณเสมอไป คุณไม่สามารถใช้ #to_i
หากคุณต้องการเก็บ "0" นำหน้า และ #delete_suffix
อาศัยสมมติฐานที่ว่าสกุลเงินเป็นดอลลาร์สหรัฐฯ เป็นหลัก
วิธีการพิเศษเป็นเหมือนเครื่องมือความแม่นยำ—เหมาะสำหรับงานเฉพาะในบริบทเฉพาะ ดังนั้นจะมีบางกรณีที่ #gsub
คือสิ่งที่เราต้องการ ใช้งานได้หลากหลายและอยู่ในใจเสมอ แต่การประมวลผลอาจยากขึ้นเล็กน้อย และมักจะช้ากว่า แม้จะช้ากว่าที่ฉันคาดไว้ สำหรับฉันแล้ว ความร่ำรวยของ Ruby ก็เป็นหนึ่งในเหตุผลที่ทำให้การทำงานด้วยสนุกมาก การชนะด้วยความเร็วเป็นโบนัสที่ดี