রুবি ডেভেলপাররা যতক্ষণ হ্যাশ ব্যবহার করেন, সহজেই মনে হয় সব কিছু জানা হয়ে গেছে।
আমি আপনাকে বলতে চাই, রুবির হ্যাশের হাতের নিচে কিছু ট্রিক আছে। এটি একটি সাধারণ কি-ভ্যালু সিস্টেম নন, বরং হ্যাশ অবজেক্ট আপনাকে কিছু খুব আকর্ষণীয় এবং সোফিস্টিকেটেড কাজ করার ক্ষমতা দেয়।
যেকোনো অবজেক্ট হ্যাশ কি হতে পারে
আগে বেড়ে যাওয়ার আগে একটি বিষয় বলছি যা očвид নাও হতে পারে। আমরা সাধারণত স্ট্রিং এবং সিম্বল হ্যাশ কি হিসেবে ব্যবহার করি, কিন্তু এর মানে নন যে আমরা অন্যান্য অবজেক্ট ব্যবহার করতে পারি না। আপনি প্রায় যেকোনো জিনিস হ্যাশ কি হিসেবে ব্যবহার করতে পারেন।
# সংখ্যাগুলো হ্যাশ কি হতে পারে {1 => "one"}[1] # "one" # রুবি কার্নেলও হ্যাশ কি হতে পারে {Kernel => 1}[Kernel] # 1 # স্পেসিফিক ক্লাসের জন্য ভ্যালু স্টোর করতে পারেন {Kernel => 1, String => 2}["hello world".class] # 2 # বুলিয়ানও হ্যাশ কি হতে পারে {true => "verdad"}[1==1] # "verdad" # জটিল অ্যারে এবং হ্যাশও হ্যাশ কি হতে পারে {[[1,0],[0,1]] => "identity matrix"}[[[1,0], [0,1]]] # "identity matrix" এই অপশনগুলোতে কিছু অন्यों চেয়ে বেশি উপকারী, কিন্তু সবই আপনার উপলব্ধ।
আপনার ডিফল্ট ভ্যালুতে নিয়ন্ত্রণ রক্ষা করতে পারেন
ধরুন আপনার একটি হ্যাশ আছে `h={ a: 1 }`। যদি আপনি এমন একটি ভ্যালু এক্সেস করতে চান যা আছে না - যেমন `h[:x]` - তবে আপনি `nil` পাবেন। কারণ `nil` হলো সব হ্যাশের ডিফল্ট ভ্যালু, যদি আপনি অন্যথায় স্পেসিফাই না করেন।
আপনি কনস্ট্রাক্টরে আর্গুমেন্ট পাস করে নতুন হ্যাশের ডিফল্ট ভ্যালু সেট করতে পারেন।
h = Hash.new("This attribute intentionally left blank") h[:a] = 1 h[:a] # 1 h[:x] # "This attribute intentionally left blank" ডাইনামিক ডিফল্ট ভ্যালু
ধ্যান দিন, কারণ এই ট্রিকই পরে 나오는 সব কিছুর ভিত্তি।
যদি কনস্ট্রাক্টরে একটি ব্লক পাস করেন, তবে আপনি প্রোগ্রামেটিক্যালি ডিফল্ট ভ্যালু জেনারেট করতে পারেন। নিচের উদাহরণে আমি ডিফল্ট ভ্যালুতে টাইমস্ট্যাম্প যোগ করেছি, যাতে ডাইনামিক্যালি জেনারেট হচ্ছে তা দেখা যায়।
h = Hash.new { |hash, key| "#{key}: #{ Time.now.to_i }" } h[:a] # "a: 1435682937" h[:a] # "a: 1435682941" h[:b] # "b: 1435682943" এটি গুরুত্বপূর্ণ কারণ "ডিফল্ট ভ্যালু" ব্লকটি ডিফল্ট ভ্যালু রিটার্ন করার পাশাপাশি অন্যান্য কাজও করতে পারে।
হ্যাশ কি না থাকলে এক্সেপশন উত্থাপন
হ্যাশের মূল সমস্যাগুলোর একটি হলো এটি সাইলেন্টলি ফেল করে। আপনি ভুলে `user[:phnoe]` লিখলেন `user[:phone]` বদলে, এবং এক্সেপশন উত্থাপন করার বদলে হ্যাশ `nil` রিটার্ন করে। কিন্তু আপনি এই বিহевиয়ার পরিবর্তন করতে পারেন।
h = Hash.new { |hash, key| raise ArgumentError.new("No hash key: #{ key }") } h[:a]=1 h[:a] # 1 h[:x] # ArgumentError উত্থাপন করে: No hash key: x এই টেকনিক ডিবাগিং এবং রিফ্যাক্টরিং-এ উপকারী হতে পারে কারণ এটি একটি নির্দিষ্ট হ্যাশে প্রযোজ্য। Hash ক্লাস মাঙ্কি-патচ করার চেয়ে এটি কম ইনট্রুসিভ।
নোট: আমি নতুন কোডে `Hash.fetch`-এর পরিবর্তে এটি ব্যবহার করার পরামর্শ দিচ্ছি না। এটি শুধু ডিবাগিং এবং রিফ্যাক্টরিং-এ রাখার একটি আকর্ষণীয় ট্রিক।
লেজিলি-জেনারেটেড লুকআপ টেবিল
এই টেকনিক কম্পিউটেশন রিজাল্ট ক্যাশ করার জন্য উপকারী। ধরা যাক আপনাকে অনেক স্কোয়ার রুট ক্যালকুলেট করতে হবে। আপনি নিচের মত একটি লেজিলি-পপুলেটেড লুকআপ টেবিল তৈরি করতে পারেন।
sqrt_lookup = Hash.new { |hash, key| hash[key] = Math.sqrt(key) } sqrt_lookup[9] # 3.0 sqrt_lookup[7] # 2.6457513110645907 sqrt_lookup # {9=>3.0, 7=>2.6457513110645907} রিকার্সিভ লেজি লুকআপ টেবিল
ধরুন আপনার একটি রিকার্সিভ ফাংশন আছে এবং আপনি প্রতিটি রিকার্সনের রেজাল্ট ক্যাশ করতে চান। ফ্যাক্টোরিয়াল ক্যালকুলেশন নিই উদাহরণস্বরূপ। "Four factorial" বা "4!" মানে "4x3x2x1"। আপনি হ্যাশ ব্যবহার করে এটি রিকার্সিভলি ইমপ্লিমেন্ট করতে পারেন। নিচের উদাহরণটি এটি সুন্দরভাবে দেখিয়েছে:
factorial = Hash.new do |h,k| if k > 1 h[k] = h[k-1] * k else h[k] = 1 end end factorial[4] # 24 factorial # {1=>1, 2=>2, 3=>6, 4=>24} ইনিশিয়ালাইজেশনের পরেও ডিফল্ট মডিফাই করা
হ্যাশ তৈরি হওয়ার পরেও আপনি ডিফল্ট ভ্যালু নিয়ন্ত্রণ করতে পারেন। এর জন্য `default` এবং `default_proc` সেটার ব্যবহার করুন।
h={} h[:a] # nil h.default = "new default" h[:a] # "new default" h.default_proc = Proc.new { Time.now.to_i } h[:a] # 1435684014 ফাইন্ড দ্য রুবি: লেজিলি ইনফিনিট নেস্টেড হ্যাশের একটি গেম
শুধু ফানের জন্য, সব উপকারী টেকনিকগুলো একসাথে বসে একটি অত্যন্ত беспরায় উদাহরণ বানাই। পুরনো টেক্সট-বেসড গেম Adventure মনে আছে? চলুন তার সবচেয়ে বোকা ভার্সন বানাই।
কল্পনা করুন আপনি একটি গুহায় আছেন। আপনি উত্তর, দক্ষিণ, পূর্ব বা পশ্চিম যেতে পারেন। এই চারটি অপশনের তিনটি আপনাকে গুহার নতুন "রুম"-এ নিয়ে যায় যেখানে আপনি এক্সপ্লোর করতে থাকেন। কিন্তু একটি অপশন আপনাকে একটি "রুবি"-এ নিয়ে যায়। তাই গেমের নাম: "ফাইন্ড দ্য রুবি"।
গুহার প্রতিটি রুম একটি হ্যাশের সাথে মিলে যায়। হ্যাশে শুধু একটি এন্ট্রি থাকে। `["n", "s", "e", "w"]`-এ থেকে র্যান্ডমলি একটি ভ্যালু "You found the ruby."। আপনি যদি ভুল চয়ন করেন, তবে একটি নতুন হ্যাশ তৈরি হয়ে ট্রিতে যোগ হয়।
generator = Proc.new do |hash, key| hash[key] = Hash.new(&generator).merge(["n", "s", "e", "w"][rand(4)] => "You found the ruby!") end dungeon = Hash.new(&generator) dungeon["n"] # <Hash ... dungeon["n"]["s"] # <Hash ... dungeon["n"]["s"]["w"] # "You found the ruby!"