আপনি কি কখনও একটি অ্যারের মধ্যে ডেটা একটি গুচ্ছ আছে, কিন্তু আপনি একটি হ্যাশ সঙ্গে মত একটি কী/মান লুকআপ করতে হবে? সৌভাগ্যবশত, রুবি অ্যারেগুলিকে কী-মানের কাঠামো হিসাবে বিবেচনা করার জন্য একটি প্রক্রিয়া সরবরাহ করে। আসুন এটি পরীক্ষা করে দেখি!
প্রবর্তন করা হচ্ছে 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"]
আমি আশা করি আপনি দেখতে পাচ্ছেন যে CSV এবং অন্যান্য ফাইল ফর্ম্যাট থেকে ডেটা নিয়ে কাজ করার সময় এটি কতটা কার্যকর হতে পারে যাতে প্রচুর কলাম থাকতে পারে৷
গতি
রুবির হ্যাশগুলি অবশ্যই Array#assoc
কে ছাড়িয়ে যাবে অধিকাংশ মানদণ্ডে। ডেটাসেট বড় হওয়ার সাথে সাথে পার্থক্যগুলি আরও স্পষ্ট হয়ে ওঠে। সর্বোপরি, হ্যাশ টেবিল অনুসন্ধানগুলি হল O(1), যখন অ্যারে অনুসন্ধানগুলি হল O(n)৷ তবে কিছু ক্ষেত্রে পার্থক্যটি আপনার চিন্তা করার জন্য যথেষ্ট বড় হবে না - এটি বিশদ বিবরণের উপর নির্ভর করে।
শুধু মজা করার জন্য, আমি 10 সারি ডেটাসেটের জন্য এবং 100,000 সারি ডেটাসেটের জন্য হ্যাশ লুকআপ বনাম 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