ট্র্যাক
/
Crystal
Crystal
/
অনুশীলনী
/
রান্নাঘরের ক্যালকুলেটর
রান্নাঘরের ক্যালকুলেটর

রান্নাঘরের ক্যালকুলেটর

লার্নিং অনুশীলনী

ভূমিকা

একটি টাপল হলো এলিমেন্টের একটি সসীম, ক্রমবদ্ধ তালিকা, যা ইমিউটেবল। টাপলে প্রতিটি পজিশনের টাইপ নির্দিষ্ট থাকতে হয়। এর ফলে কম্পাইলার জানে প্রতিটি পজিশনে কোন টাইপ আছে। টাপলে ব্যবহৃত টাইপ প্রতিটি পজিশনে আলাদা হতে পারে, তবে টাইপগুলো কম্পাইল টাইমে জানা থাকতে হবে।

টাপল তৈরি করা

টাপলের মানগুলোর টাইপ কম্পাইলের সময় নির্ধারণ করা যায় কি না, তার উপর নির্ভর করে টাপল বিভিন্ন উপায়ে তৈরি করা যায়। মানগুলো কম্পাইল টাইমে জানা থাকলে টাপল লিটারাল সিনট্যাক্স ব্যবহার করে টাপল তৈরি করা যায়, নাহলে সেগুলো স্পষ্টভাবে ডিক্লেয়ার করতে হয়। এটাও গুরুত্বপূর্ণ যে মানগুলোর টাইপ টাপলে উল্লেখ করা টাইপের সাথে মিলতে হবে এবং মানের সংখ্যা উল্লেখ করা টাইপের সংখ্যার সাথে মিলতে হবে। টাপল লিটারাল সিনট্যাক্স দিয়ে ডিফাইন করার একটি উদাহরণ এখানে:

tuple = {1, "foo", 'c'} # Tuple(Int32, String, Char)

Tuple ক্লাস ব্যবহার করেও টাপল তৈরি করা যায়।

tuple = Tuple(Int32, String, Char).new(1, "foo", 'c')

বিকল্পভাবে, আপনি টাপলে অ্যাসাইন করা ভ্যারিয়েবলের টাইপ স্পষ্টভাবে উল্লেখ করতে পারেন।

tuple : Tuple(Int32, String, Char) = {1, "foo", 'c'}

টাপলের টাইপ স্পষ্টভাবে উল্লেখ করা কাজে লাগতে পারে, কারণ এতে কোনো পজিশনে ইউনিয়ন টাইপ থাকবে বলে ডিফাইন করা যায়। এর মানে হলো একটি পজিশনে একাধিক টাইপ থাকতে পারে।

tuple : Tuple(Int32 | String, String, Char) = {1, "foo", 'c'}

রূপান্তর

অ্যারে থেকে টাপল তৈরি করা

Tuple ক্লাসের from মেথড ব্যবহার করে আপনি একটি অ্যারে থেকে টাপল তৈরি করতে পারেন। এর জন্য টাপলের টাইপ উল্লেখ করা প্রয়োজন।

array = [1, "foo", 'c']
tuple = Tuple(Int32, String, Char).from(array)

অ্যারেতে রূপান্তর

to_a মেথড ব্যবহার করে আপনি একটি টাপলকে অ্যারেতে রূপান্তর করতে পারেন। ফলাফল অ্যারের এলিমেন্ট টাইপ হবে টাপলের প্রতিটি ফিল্ডের টাইপের ইউনিয়ন।

tuple = {1, "foo", 'c'}
array = tuple.to_a
array # => [1, "foo", 'c']

এলিমেন্ট অ্যাক্সেস করা

অ্যারের মতোই টাপল জিরো-ইনডেক্সড, অর্থাৎ প্রথম এলিমেন্টটি ইনডেক্স 0-এ থাকে। তবে অ্যারের বিপরীতে প্রতিটি এলিমেন্টের টাইপ নির্দিষ্ট এবং কম্পাইল টাইমে জানা থাকে, তাই টাপল ইনডেক্স করার সময় এলিমেন্টের টাইপ পজিশন অনুযায়ী নির্দিষ্ট হয়। টাপলের কোনো এলিমেন্ট অ্যাক্সেস করতে আপনি [] অপারেটর ব্যবহার করতে পারেন।

array = [1, "foo", 'c']
array[0]         # => 1
typeof(array[0]) # => Int32 | String | Char

tuple = {1, "foo", 'c'}
tuple[0]         # => 1
typeof(tuple[0]) # => Int32

অ্যারে থেকে এলিমেন্ট অ্যাক্সেস করার তুলনায় আরেকটি পার্থক্য হলো, ইনডেক্স উল্লেখ করা থাকলে কম্পাইলার যাচাই করে যে ইনডেক্সটি টাপলের সীমার ভেতরে আছে কি না। এর মানে হলো রানটাইম এররের বদলে আপনি একটি কম্পাইল টাইম এরর পাবেন।

tuple = {1, "foo", 'c'}
tuple[3]
# => Error: index out of bounds for Tuple(Int32, String, Char) (3 not in -3..2)

তবে ইনডেক্স কোনো ভ্যারিয়েবলে রাখা থাকলে কম্পাইলার কম্পাইল টাইমে যাচাই করতে পারবে না যে ইনডেক্সটি টাপলের সীমার ভেতরে আছে কি না, বরং একটি রানটাইম এরর দেবে।

সাবটাপল

একটি রেঞ্জসহ [] অপারেটর ব্যবহার করে আপনি টাপলের একটি সাবটাপল পেতে পারেন। যা ফেরত আসে তা হলো উল্লেখ করা রেঞ্জের এলিমেন্টগুলো নিয়ে গঠিত একটি নতুন টাপল। রেঞ্জটি কম্পাইল টাইমে দিতে হবে, নাহলে কম্পাইলার সাবটাপলের এলিমেন্টগুলোর টাইপ জানতে পারবে না। এর মানে হলো রেঞ্জটি একটি রেঞ্জ লিটারাল হতে হবে, কোনো ভ্যারিয়েবলে অ্যাসাইন করা যাবে না।

tuple = {1, "foo", 'c'}
subtuple = tuple[0..1] # Tuple(Int32, String)

i = 0..1
tuple[i]
# Error: Tuple#[](Range) can only be called with range literals known at compile-time

কখন টাপল ব্যবহার করবেন

নির্দিষ্ট সংখ্যক মান একসাথে গুছিয়ে রাখতে চাইলে টাপল কাজে লাগে, যখন সেই মানগুলোর টাইপ কম্পাইল টাইমে জানা থাকে। কারণ টাপলের ইমিউটেবিলিটির সুবাদে এগুলো অ্যারের চেয়ে কম মেমরি নেয় এবং দ্রুততর। আরেকটি ব্যবহারের ক্ষেত্র হলো একটি মেথড থেকে একাধিক মান রিটার্ন করা। মানগুলোর টাইপ আলাদা হলে এটি বিশেষভাবে সহায়ক, কারণ টাপলের প্রতিটি পজিশনে আলাদা টাইপ থাকতে পারে।

যে ডেটা স্ট্রাকচার আকারে বাড়তে বা কমতে পারে, বা যেটি প্রায়ই পরিবর্তন করতে হয়, এমন কিছু দরকার হলে টাপল ব্যবহার করা উচিত নয়।

সিম্বল হলো নামযুক্ত আইডেন্টিফায়ার, যা দিয়ে কোনো মানকে বোঝানো যায়। সিম্বল তৈরি হয় সিম্বল লিটারাল দিয়ে, অর্থাৎ একটি নামের আগে : ক্যারেক্টার বসিয়ে, যেমন :foo। এগুলো কোটেশন দিয়েও লেখা যায়, যেমন :"foo", যা দিয়ে যেমন নামের মধ্যে স্পেস রাখা সম্ভব হয়।

:foo           # => :foo
:"foo boo"     # => :"foo boo"
:foo == :"foo" # => true

ভাষার অনেক জায়গায় সিম্বল ব্যবহৃত হয়, যেমন নেমডটাপলে কী (key) হিসেবে এবং মেথড ও ভ্যারিয়েবলের নাম বোঝাতে।

Crystal-এ সিম্বল

Crystal-এ সিম্বল Ruby থেকে বেশ আলাদা। Crystal-এ একটি সিম্বল এক ধরনের কনস্ট্যান্ট, এবং তাই এটি কম্পাইল টাইমে অ্যাসাইন করা হয়। এর মানে হলো সিম্বল ডাইনামিকভাবে তৈরি করা যায় না, যা Ruby-তে সম্ভব।

Crystal-এ সিম্বল Int32 হিসেবে রিপ্রেজেন্ট করা হয়, যা তাদের খুবই দক্ষ করে তোলে।

রূপান্তর

সিম্বলকে স্ট্রিংয়ে রূপান্তর করা যায়, কিন্তু এর উল্টোটা নয়। কারণ সিম্বল তৈরি হয় কম্পাইল টাইমে, আর স্ট্রিং তৈরি হয় রানটাইমে।

:foo.to_s # => "foo"

নির্দেশনা

বন্ধুদের জন্য কুকি বেক করার প্রস্তুতি নেওয়ার সময় আপনি দেখলেন যে, রেসিপিতে ব্যবহৃত কিছু মাপ আপনাকে রূপান্তর করতে হবে। যেহেতু আপনি কেবল মেট্রিক পদ্ধতির সাথে পরিচিত, তাই নিজের সুবিধার জন্য আমেরিকান বেকিংয়ের প্রচলিত মাপগুলোকে মিলিলিটার (mL)-এ রূপান্তর করার একটি উপায় আপনাকে বের করতে হবে।

আপনার সমাধানের জন্য এই রূপান্তর ছকটি ব্যবহার করুন:

রূপান্তরের একক ভলিউম মিলিলিটার (mL)-এ
mL 1 1
আমেরিকান কাপ 1 240
আমেরিকান ফ্লুইড আউন্স 1 30
আমেরিকান চা-চামচ 1 5
আমেরিকান টেবিল-চামচ 1 15

প্রশিক্ষণরত একজন প্রতিভাবান প্রোগ্রামার হিসেবে আপনি সিদ্ধান্ত নিলেন যে, তালিকাভুক্ত যেকোনো একক থেকে অন্য যেকোনো এককে (এমনকি একই এককে) রূপান্তর সহজ করতে মিলিলিটারকে একটি মধ্যবর্তী একক হিসেবে ব্যবহার করবেন।

1. একটি ভলিউম-জোড়া থেকে সংখ্যাসূচক অংশটি বের করুন

KitchenCalculator.get_volume মেথডটি ইমপ্লিমেন্ট করুন। একটি ভলিউম-জোড়া টিউপল দেওয়া হলে, এটির কেবল সংখ্যাসূচক অংশটি রিটার্ন করা উচিত।

KitchenCalculator.get_volume({:cup, 2.0})
# => 2.0

2. ভলিউম-জোড়াটিকে মিলিলিটারে রূপান্তর করুন

KitchenCalculator.to_milliliter মেথডটি ইমপ্লিমেন্ট করুন। একটি ভলিউম-জোড়া টিউপল দেওয়া হলে, রূপান্তর ছক ব্যবহার করে এটির ভলিউমকে মিলিলিটারে রূপান্তর করা উচিত।

KitchenCalculator.to_milliliter({:cup, 2.5})
# => {:milliliter, 600.0}

3. মিলিলিটার ভলিউম-জোড়াটিকে অন্য এককে রূপান্তর করুন

KitchenCalculator.from_milliliter মেথডটি ইমপ্লিমেন্ট করুন। একটি ভলিউম-জোড়া টিউপল ও কাঙ্ক্ষিত একক দেওয়া হলে, রূপান্তর ছক ব্যবহার করে ভলিউমটিকে কাঙ্ক্ষিত এককে রূপান্তর করা উচিত।

KitchenCalculator.from_milliliter({:milliliter, 1320.0}, :cup)
# => {:cup, 5.5}

4. যেকোনো একক থেকে যেকোনো এককে রূপান্তর করুন

KitchenCalculator.convert মেথডটি ইমপ্লিমেন্ট করুন। একটি ভলিউম-জোড়া টিউপল ও কাঙ্ক্ষিত একক দেওয়া হলে, প্রদত্ত ভলিউমটিকে কাঙ্ক্ষিত এককে রূপান্তর করা উচিত।

KitchenCalculator.convert({:teaspoon, 9.0}, :tablespoon)
# => {:tablespoon, 3.0}
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি একটি নতুন উইন্ডো বা ট্যাবে খোলে
Crystal Exercism

রান্নাঘরের ক্যালকুলেটর শুরু করতে প্রস্তুত?

Exercism-এ সাইন আপ করুন, Crystal ট্র্যাকের 26টি কনসেপ্ট142টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।