Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ Ruby Associative Arrays: ใช้ Array#assoc และ #rassoc สำหรับ Key-Value Lookups

เคยมี data เยอะใน array แต่อยาก key/value lookup เหมือน hash? Ruby มี mechanism ให้ treat arrays เป็น key-value structures มาดู!

Introducing Array#assoc และ Array#rassoc

สมมติได้ magical stock-picking machine ทุกไม่กี่นาที吐 recommendation buy/sell stock hook กับคอมพิวเตอร์ได้ stream data แบบนี้:

picks = [ ["AAPL", "buy"], ["GOOG", "sell"], ["MSFT", "sell"] ] 

หา guidance ล่าสุด Google 用 Array#assoc method:

# Returns the first row of data where row[0] == "GOOG" picks.assoc("GOOG") # => ["GOOG", "sell"] 

หา "sell" recommendation ล่าสุด 用 Array#rassoc:

# Returns the first row of data where row[1] == "sell" picks.rassoc("sell") # => ["GOOG", "sell"] 

ไม่เจอ match methods return nil:

picks.assoc("CSCO") # => nil picks.rassoc("hold") # => nil 

Historical Data

Hashes ไม่สามารถมี more than one value สำหรับ single key แต่ arrays มี duplicates ได้เท่าไหร่ก็ได้ assoc และ rassoc ทำ sensible thing คืน first matching row ทำให้ทำสิ่งน่าสนใจได้

Stock picking machine ให้ stream of data เปลี่ยนใจเกี่ยว company บอก buy ตัวที่เคยบอก sell data 长这样:

picks = [ ["GOOG", "buy"], ["AAPL", "sell"], ["AAPL", "buy"], ["GOOG", "sell"], ["MSFT", "sell"] ] 

ถ้า put data ใน hash update recommendation สำหรับ stock ตัวหนึ่ง lose previous recommendations ไม่ใช่กับ array prepend recommendations เข้า array รู้ว่า Array#assoc ให้ most recent recommendation เสมอ

# Returns the first row of data where row[0] == "GOOG" picks.assoc("GOOG") # => ["GOOG", "buy"] 

ได้ key-value goodness ของ hash พร้อม free audit trail

More Than Two Columns

Assoc ไม่ limited สอง columns per array columns เยอะเท่าไหร่ก็ได้ สมมติเพิ่ม timestamp ให้ buy/sell recommendation

picks = [ ["AAPL", "buy", "2015-08-17 12:11:55 -0700"], ["GOOG", "sell", "2015-08-17 12:10:00 -0700"], ["MSFT", "sell", "2015-08-17 12:09:00 -0700"] ] 

用 assoc หรือ rassoc ได้ timestamp ด้วย:

# The entire row is returned picks.assoc("GOOG") # => ["GOOG", "sell", "2015-08-17 12:10:00 -0700"] 

ใช้งานได้ดีเวลา deal กับ data จาก CSV และ file formats ที่มี columns เยอะ

Speed

Ruby hashes outperform Array#assoc ใน benchmarks ส่วนใหญ่ dataset ใหญ่ ความต่างชัดเจน Hash table searches O(1) array searches O(n) แต่มากับ case ความต่างไม่ใหญ่พอจะกังวล ขึ้นกับ details

เขียน benchmark 簡單 เปรียบเทียบ hash lookup vs assoc 10 rows และ 100,000 rows คาดการณ์ hash และ array ใกล้เคียง small dataset large dataset hash dominate array

...though to be fair ผม search last element ใน array worst case scenario สำหรับ array searches

require 'benchmark/ips' require 'securerandom' Benchmark.ips do |x| x.time = 5 x.warmup = 2 short_array = (0..10).map { |i| [SecureRandom.hex(), i] } short_hash = Hash[short_array] short_key = short_array.last.first long_array = (0..100_000).map { |i| [SecureRandom.hex(), i] } long_hash = Hash[long_array] long_key = short_array.last.first x.report("short_array") { short_array.assoc(short_key) } x.report("short_hash") { short_hash[short_key] } x.report("long_array") { long_array.assoc(long_key) } x.report("long_hash") { long_hash[long_key] } x.compare! end # Calculating ------------------------------------- # short_array 91.882k i/100ms # short_hash 149.430k i/100ms # long_array 19.000 i/100ms # long_hash 152.086k i/100ms # ------------------------------------------------- # short_array 1.828M (± 3.4%) i/s - 9.188M # short_hash 6.500M (± 4.8%) i/s - 32.426M # long_array 205.416 (± 3.9%) i/s - 1.026k # long_hash 6.974M (± 4.2%) i/s - 34.828M # Comparison: # long_hash: 6974073.6 i/s # short_hash: 6500207.2 i/s - 1.07x slower # short_array: 1827628.6 i/s - 3.82x slower # long_array: 205.4 i/s - 33950.98x slower