क्या आपने कभी किसी सरणी में डेटा का एक गुच्छा लिया है, लेकिन एक कुंजी/मूल्य लुकअप करने की आवश्यकता है जैसे आप हैश के साथ करेंगे? सौभाग्य से, रूबी सरणियों को कुंजी-मूल्य संरचनाओं के रूप में व्यवहार करने के लिए एक तंत्र प्रदान करता है। आइए इसे देखें!
पेश है Array#assoc
और Array#rassoc
कल्पना कीजिए कि आपको एक जादुई स्टॉक-पिकिंग मशीन दी गई है। हर कुछ मिनटों में यह स्टॉक खरीदने या बेचने की सिफारिश करता है। आपने इसे अपने कंप्यूटर से जोड़ने और डेटा की एक स्ट्रीम प्राप्त करने में कामयाबी हासिल की है जो इस तरह दिखती है:
picks = [
["AAPL", "buy"],
["GOOG", "sell"],
["MSFT", "sell"]
]
Google के लिए नवीनतम मार्गदर्शन प्राप्त करने के लिए, आप Array#assoc
. का उपयोग कर सकते हैं तरीका। यहाँ जो दिखता है वह है:
# Returns the first row of data where row[0] == "GOOG"
picks.assoc("GOOG") # => ["GOOG", "sell"]
नवीनतम "बिक्री" अनुशंसा खोजने के लिए, आप Array#rassoc
. का उपयोग कर सकते हैं विधि।
# Returns the first row of data where row[1] == "sell"
picks.rassoc("sell") # => ["GOOG", "sell"]
यदि कोई मिलान नहीं मिलता है, तो विधियाँ शून्य हो जाती हैं:
picks.assoc("CSCO") # => nil
picks.rassoc("hold") # => nil
ऐतिहासिक डेटा
हैश में एक कुंजी के लिए एक से अधिक मान नहीं हो सकते हैं। लेकिन सरणियों में जितने चाहें उतने डुप्लिकेट हो सकते हैं। इस मामले में assoc और rassoc विधियां समझदार काम करती हैं और उन्हें मिलने वाली पहली मिलान पंक्ति वापस कर देती हैं। यह हमें कुछ बहुत ही रोचक चीजें करने देता है।
हमारी काल्पनिक स्टॉक पिकिंग मशीन डेटा की एक धारा प्रदान करती है। आखिरकार, यह एक विशेष कंपनी के बारे में अपना विचार बदलने जा रहा है और मुझे वह खरीदने के लिए कहेगा जो उसने पहले मुझे बेचने के लिए कहा था। उस स्थिति में हमारा डेटा ऐसा दिखता है:
picks = [
["GOOG", "buy"],
["AAPL", "sell"],
["AAPL", "buy"],
["GOOG", "sell"],
["MSFT", "sell"]
]
अगर मैं इस सभी डेटा को हैश में डाल रहा था, तो किसी विशेष स्टॉक के लिए अनुशंसा को अपडेट करने से मैं उस स्टॉक के लिए पिछली सभी अनुशंसाओं को खो दूंगा। सरणी के साथ ऐसा नहीं है। मैं सरणी के लिए अनुशंसाओं को पूर्ववत करना जारी रख सकता हूं, यह जानते हुए कि Array#assoc मुझे हमेशा नवीनतम अनुशंसा देगा।
# Returns the first row of data where row[0] == "GOOG"
picks.assoc("GOOG") # => ["GOOG", "buy"]
इसलिए हमें एक मुफ़्त ऑडिट ट्रेल के साथ-साथ हैश की कुंजी-मूल्य की अच्छाई मिलती है।
दो से अधिक कॉलम
assoc के बारे में एक और साफ बात यह है कि आप प्रति सरणी केवल दो कॉलम तक ही सीमित नहीं हैं। आपके पास जितने चाहें उतने कॉलम हो सकते हैं। मान लें कि आपने प्रत्येक खरीद/बिक्री अनुशंसा में टाइमस्टैम्प जोड़ा है।
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
, हमें टाइमस्टैम्प भी मिलेगा:
# The entire row is returned
picks.assoc("GOOG") # => ["GOOG", "sell", "2015-08-17 12:10:00 -0700"]
मुझे आशा है कि आप देख सकते हैं कि सीएसवी और अन्य फ़ाइल स्वरूपों के डेटा के साथ काम करते समय यह कितना उपयोगी हो सकता है जिसमें बहुत सारे कॉलम हो सकते हैं।
गति
रूबी के हैश निश्चित रूप से बेहतर प्रदर्शन करेंगे Array#assoc
अधिकांश बेंचमार्क में। जैसे-जैसे डेटासेट बड़ा होता जाता है, अंतर अधिक स्पष्ट होते जाते हैं। आखिरकार, हैश टेबल खोज ओ (1) हैं, जबकि सरणी खोज ओ (एन) हैं। हालांकि कुछ मामलों में अंतर इतना बड़ा नहीं होगा कि आप चिंता न करें - यह विवरण पर निर्भर करता है।
बस मनोरंजन के लिए, मैंने 10 पंक्ति डेटासेट और 100,000 पंक्ति डेटासेट के लिए हैश लुकअप बनाम असोक की तुलना करते हुए सरल बेंचमार्क लिखा। जैसा कि अपेक्षित था, हैश और सरणी ने छोटे डेटा सेट के साथ समान प्रदर्शन किया। बड़े डेटासेट के साथ, हैश सरणी पर हावी हो गया।
... हालांकि निष्पक्ष होने के लिए, मैं सरणी में अंतिम तत्व की खोज कर रहा हूं, जो सरणी खोजों के लिए सबसे खराब स्थिति है।
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