আপনার কি কখনো একটি অ্যারেতে অনেক ডেটা থাকায় কিন্তু হ্যাশের মত কী/ভ্যালু লুকআপ করার দরকার পড়েছে? خوشবর্তমান, রুবি অ্যারেকে কী-ভ্যালু স্ট্রাকচার হিসেবে ব্যবহার করার একটি মেকানিজম প্রদান করে। আসুন চেক করি!
Array#assoc এবং Array#rassoc পরিচিতি
কল্পনা করুন আপনাকে একটি ম্যাজিক্যাল স্টক-পিকিং মেশিন দেওয়া হয়েছে। প্রতি কয়েক মিনিটে এটি একটি স্টক কেনা বা বিক্রি করার সুপারিশস্পিট আউট করে। আপনি এটিকে আপনার কম্পিউটারের সাথে হুক আপ করতে সফল হয়েছেন, এবং এমন একটি ডেটা স্ট্রিম পাচ্ছেন:
picks = [ ["AAPL", "buy"], ["GOOG", "sell"], ["MSFT", "sell"] ] গুগলের জন্য সবচেয়ে সাম্প্রতিক গাইডেন্স খুঁজতে আপনি Array#assoc মেথড ব্যবহার করতে পারেন। সেটি কেমন দেখাবে সেটা নিচে:
# সেটি রিটার্ন করে ডেটার প্রথম রো যেখানে row[0] == "GOOG" picks.assoc("GOOG") # => ["GOOG", "sell"] সবচেয়ে সাম্প্রতিক "sell" সুপারিশন খুঁজতে আপনি Array#rassoc মেথড ব্যবহার করতে পারেন।
# সেটি রিটার্ন করে ডেটার প্রথম রো যেখানে row[1] == "sell" picks.rassoc("sell") # => ["GOOG", "sell"] যদি কোনো ম্যাচ না পাওয়া যায়, মেথডগুলো nil রিটার্ন করে:
picks.assoc("CSCO") # => nil picks.rassoc("hold") # => nil হিস্টরিক্যাল ডেটা
হ্যাশে একটি কী-এর জন্য একাধিক ভ্যালু থাকতে পারে না। কিন্তু অ্যারেতে আপনার ইচ্ছামতো ডুপ্লিকেট থাকতে পারে। এই কেসে assoc এবং rassoc মেথডগুলো সেনসিবল কাজ করে এবং প্রথম ম্যাচিং রোটি রিটার্ন করে। এটি আমাদের কিছু খুব ইন্টেরেস্টিং জিনিস করতে দেয়।
আমাদের কাল্পনিক স্টক পিকিং মেশিন একটি ডেটা স্ট্রিম প্রদান করে। একদিন এটি একটি নির্দিষ্ট কোম্পানির বিষয়ে মনে মনে করবে এবং আমাকে বলবে কেনো যা এটা আগে বলেছিল বিক্রি করার জন্য। সেক্ষেত্রে আমাদের ডেটা হবে এমন:
picks = [ ["GOOG", "buy"], ["AAPL", "sell"], ["AAPL", "buy"], ["GOOG", "sell"], ["MSFT", "sell"] ] যদি আমি এই সকল ডেটা একটি হ্যাশে রাখতাম, একটি নির্দিষ্ট স্টকের সুপারিশন আপডেট করলে সেই স্টকের পिछলা সুপারিশনগুলো হারিয়ে যেতাম। অ্যারেতে এভাবে নয়। আমি সুপারিশনগুলো অ্যারেতে প্রিপেন্ড করতে থাকতে পারি, জেনেরিক Array#assoc সবসময় আমাকে সবচেয়ে সাম্প্রতিক সুপারিশন দেবে।
# সেটি রিটার্ন করে ডেটার প্রথম রো যেখানে 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 ব্যবহার করব, আমরা টাইমস্ট্যাম্পও পাবো:
# পুরো রোটি রিটার্ন হয় picks.assoc("GOOG") # => ["GOOG", "sell", "2015-08-17 12:10:00 -0700"] আশা করি আপনি বুঝতে পারছেন CSV এবং অন্যান্য ফাইল ফরম্যাট যেগুলো অনেক কলাম 가질 수 있다, সেগুলোর সাথে ডিল করার সময় এটি কতটুকু ইউজফুল হতে পারে।
স্পিড
রুবির হ্যাশ নিশ্চিতভাবেই Array#assoc-এর চেয়ে অধিকাংশ বেঞ্চমার্কে আউটপারফর্ম করবে। ডেটাসেট যত বড় হয়, পার্থক্যটো তত স্পষ্ট হয়।畢竟, হ্যাশ টেবিল সার্চ O(1), আর অ্যারে সার্চ O(n)। যাইহোক, অনেক কেসে পার্থক্যটো इतना বড় নয় যে আপনি চিন্তা করবেন - এটি ডিটেইলসের ওপর নির্ভর করে।
শুধু ফান এর জন্য, আমি একটি সিম্পল বেঞ্চমার্ক লিখলাম হ্যাশ লুকআপ vs assoc ১০ রো ডেটাসেট এবং ১০০,০০০ রো ডেটাসেটের জন্য। আশা অনুযায়ী, ছোট ডেটাসেটে হ্যাশ এবং অ্যারে সমান পারফর্ম করে। বড় ডেটাসেটে, হ্যাশ অ্যারেকে ডоминиেট করে।
...ন্যায়সঙ্গত হলে, আমি অ্যারেতে লাস্ট এলিমেন্ট খুঁজছি, যা অ্যারে সার্চের ওর্স্ট কেস সিনেরিও।
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