ডিকম্পোজিশন বলতে একটি কালেকশন, যেমন কোনো Array বা Hash-এর এলিমেন্টগুলো বের করে আনার কাজকে বোঝায়।
এরপর ডিকম্পোজ করা মানগুলো একই স্টেটমেন্টের মধ্যে ভ্যারিয়েবলে অ্যাসাইন করা যায়।
মাল্টিপল অ্যাসাইনমেন্ট হলো একই স্টেটমেন্টের মধ্যে ডিকম্পোজ করা মান একাধিক ভ্যারিয়েবলে অ্যাসাইন করার ক্ষমতা।
এতে কোড আরও সংক্ষিপ্ত ও পাঠযোগ্য হয়, আর এটি করা হয় অ্যাসাইন করার ভ্যারিয়েবলগুলো কমা দিয়ে আলাদা করে, যেমন first, second, third = [1, 2, 3]।
স্প্ল্যাট অপারেটর (*) এবং ডাবল স্প্ল্যাট অপারেটর (**) প্রায়ই ডিকম্পোজিশনের কাজে ব্যবহৃত হয়।
স্প্ল্যাট অপারেটর (*) দিয়ে একাধিক অ্যারেকে একটি অ্যারেতে মিলিয়ে ফেলা যায়, প্রতিটিকে ডিকম্পোজ করে একটি নতুন সাধারণ অ্যারেতে পরিণত করার মাধ্যমে।
ডাবল স্প্ল্যাট অপারেটর (**) দিয়ে একাধিক হ্যাশকে একটি হ্যাশে মিলিয়ে ফেলা যায়, প্রতিটিকে ডিকম্পোজ করে একটি নতুন সাধারণ হ্যাশে পরিণত করার মাধ্যমে।
এই সিনট্যাক্স ব্যবহার করা হয় পজিশনাল আর্গুমেন্ট হিসেবে গৃহীত একাধিক মানের সঙ্গে এমন একটি ক্ষেত্রের পার্থক্য বোঝাতে, যেখানে যেকোনো সংখ্যক কিওয়ার্ড আর্গুমেন্ট গ্রহণ করা হয়।
স্প্ল্যাট অপারেটর (*) কোনো কালেকশন ছাড়া ব্যবহার করলে এটি একগুচ্ছ মানকে একটি অ্যারেতে প্যাক (বা কম্পোজ) করে।
মাল্টিপল অ্যাসাইনমেন্টে এটি প্রায়ই ব্যবহৃত হয়, আলাদা অ্যাসাইনমেন্ট নেই এমন সব "বাকি" এলিমেন্টকে একটি ভ্যারিয়েবলে একত্র করার জন্য।
যেকোনো সংখ্যক পজিশনাল বা কিওয়ার্ড আর্গুমেন্ট নেয় এমন মেথড ব্যবহার বা ডিফাইন করার সময় Ruby-তে এই ডিকম্পোজ/কম্পোজ আচরণ ব্যবহার করা কমন।
আপনি প্রায়ই দেখবেন এসব আর্গুমেন্ট def some_method(*arguments, **keyword_arguments) হিসেবে ডিফাইন করা হয় এবং আর্গুমেন্টগুলো some_method(*some_array, **some_hash) হিসেবে ব্যবহৃত হয়।
*<variable_name> ও **<variable_name>-কে * ও **-এর সঙ্গে গুলিয়ে ফেলা উচিত নয়।
* ও ** যথাক্রমে গুণ ও সূচকের জন্য ব্যবহৃত হয়, আর *<variable_name> ও **<variable_name> ব্যবহৃত হয় কম্পোজিশন ও ডিকম্পোজিশন অপারেটর হিসেবে।
মাল্টিপল অ্যাসাইনমেন্ট দিয়ে আপনি এক লাইনেই একাধিক ভ্যারিয়েবলে অ্যাসাইন করতে পারেন।
মানগুলো আলাদা করতে কমা , ব্যবহার করুন:
>> a, b = 1, 2
=> [1, 2]
>> a
=> 1
মাল্টিপল অ্যাসাইনমেন্ট কেবল একটি ডেটা টাইপেই সীমাবদ্ধ নয়:
>> x, y, z = 1, "Hello", true
=> [1, "Hello", true]
>> x
=> 1
>> y
=> 'Hello'
>> z
=> true
মাল্টিপল অ্যাসাইনমেন্ট দিয়ে অ্যারের এলিমেন্টগুলো অদলবদল করা যায়। সর্টিং অ্যালগরিদমে এই কাজটি বেশ কমন। যেমন:
>> numbers = [1, 2]
=> [1, 2]
>> numbers[0], numbers[1] = numbers[1], numbers[0]
=> [2, 1]
>> numbers
=> [2, 1]
এটিকে "প্যারালাল অ্যাসাইনমেন্ট" নামেও ডাকা হয়, আর এটি একটি টেম্পোরারি ভ্যারিয়েবল এড়াতে ব্যবহার করা যায়।
মানের চেয়ে ভ্যারিয়েবল বেশি হলে, বাড়তি ভ্যারিয়েবলগুলোতে nil অ্যাসাইন হবে:
>> a, b, c = 1, 2
=> [1, 2]
>> b
=> 2
>> c
=> nil
ভ্যারিয়েবলের চেয়ে মান বেশি হলে, বাড়তি মানগুলো উপেক্ষিত হবে:
>> a, b, c = 1, 2, 3, 4
>> b
=> 2
>> c
=> 3
Ruby-তে অ্যারে/হ্যাশ-এর এলিমেন্টগুলো ডিকম্পোজ করে আলাদা আলাদা ভ্যারিয়েবলে রাখা সম্ভব। যেহেতু অ্যারে-এর মানগুলো একটি ইনডেক্স ক্রমে থাকে, তাই সেগুলোও একই ক্রমে ভ্যারিয়েবলগুলোতে আনপ্যাক করা হয়:
>> fruits = ["apple", "banana", "cherry"]
>> x, y, z = fruits
>> x
=> "apple"
কোনো মানের দরকার না থাকলে _ দিয়ে বোঝাতে পারেন যে সেটি "সংগ্রহ করা হয়েছে কিন্তু ব্যবহার করা হয়নি":
>> fruits = ["apple", "banana", "cherry"]
>> _, _, z = fruits
>> z
=> "cherry"
একটি অ্যারের ভেতরে থাকা অ্যারে থেকে মান ডিকম্পোজ ও অ্যাসাইন করা (যাকে নেস্টেড অ্যারে-ও বলা হয়) সাধারণ ডিকম্পোজিশনের মতোই কাজ করে, তবে মানগুলোর প্রসঙ্গ বা অবস্থান স্পষ্ট করতে ডিলিমিটেড ডিকম্পোজিশন এক্সপ্রেশন (()) দরকার হয়:
>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>> (a, b), (c, d) = fruits_vegetables
>> a
=> "apple"
>> d
=> "potato"
আপনি একটি নেস্টেড অ্যারের কেবল একটি অংশও গভীরভাবে আনপ্যাক করতে পারেন:
>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>> a, (c, d) = fruits_vegetables
>> a
=> ["apple", "banana"]
>> c
=> "carrot"
ডিকম্পোজিশনে ভ্যারিয়েবলগুলোর অবস্থান ভুল হলে এবং/অথবা মানের সংখ্যা ভুল হলে, আপনি একটি সিনট্যাক্স এরর পাবেন:
fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
(a, b), (d) = fruits_vegetables
syntax error, unexpected ')', expecting '.' or &. or :: or '['
((a, b), (d)) = fruits_vegetables
এখানে পরীক্ষা করে দেখুন, বুঝতে পারবেন যে ডান দিকে থাকা মানগুলো নয়, বরং প্রথম প্যাটার্নটিই নিয়ন্ত্রণ করে। সিনট্যাক্স এররটি ডেটা স্ট্রাকচারের সঙ্গে সম্পর্কিত নয়।
*) দিয়ে একটি অ্যারে ডিকম্পোজ করাযখন আপনি একটি [অ্যারে ডিকম্পোজ করেন][decomposition], তখন স্প্ল্যাট অপারেটর (*) দিয়ে "বাকি" মানগুলো ধরে রাখতে পারেন।
এটি অ্যারে স্লাইস করার চেয়ে স্পষ্ট (যা কিছু ক্ষেত্রে কম পাঠযোগ্য)।
যেমন, আমরা প্রথম এলিমেন্টটি বের করে বাকি মানগুলো প্রথম এলিমেন্ট ছাড়া একটি নতুন অ্যারেতে অ্যাসাইন করতে পারি:
>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *last = fruits
>> x
=> "apple"
>> last
=> ["banana", "cherry", "orange", "kiwi", "melon", "mango"]
আমরা অ্যারে-এর শুরু ও শেষের মানগুলো বের করে মাঝের সব মান একসঙ্গে একটি দলে ভাগ করতে পারি:
>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>> x, *middle, y, z = fruits
>> y
=> "melon"
>> middle
=> ["banana", "cherry", "orange", "kiwi"]
গভীর ডিকম্পোজিশনেও আমরা * ব্যবহার করতে পারি:
>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
>> (a, *rest), b = fruits_vegetables
>> a
=> "apple"
>> rest
=> ["banana", "melon"]
Hash ডিকম্পোজ করাএকটি হ্যাশ ডিকম্পোজ করা একটি অ্যারে ডিকম্পোজ করার চেয়ে একটু আলাদা। একটি হ্যাশ আনপ্যাক করতে হলে প্রথমে সেটিকে একটি অ্যারেতে রূপান্তর করতে হবে। নাহলে ডিকম্পোজিশন হবে না:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory
>> x
=> {:apple=>6, :banana=>2, :cherry=>3}
>> y
=> nil
একটি Hash-কে অ্যারেতে রূপান্তর করতে আপনি to_a মেথড ব্যবহার করতে পারেন:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> fruits_inventory.to_a
=> [[:apple, 6], [:banana, 2], [:cherry, 3]]
>> x, y, z = fruits_inventory.to_a
>> x
=> [:apple, 6]
আপনি যদি কী (key)গুলো আনপ্যাক করতে চান, তাহলে keys মেথড ব্যবহার করতে পারেন:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory.keys
>> x
=> :apple
আর মানগুলো আনপ্যাক করতে চাইলে values মেথড ব্যবহার করতে পারেন:
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> x, y, z = fruits_inventory.values
>> x
=> 6
কম্পোজ করা হলো একাধিক মানকে একটি অ্যারেতে একত্র করে একটি ভ্যারিয়েবলে অ্যাসাইন করার ক্ষমতা। এটি কাজে লাগে যখন আপনি মানগুলো ডিকম্পোজ করতে, পরিবর্তন করতে, আর পরে ফলাফলগুলো আবার একটি ভ্যারিয়েবলে কম্পোজ করতে চান। এটি ২টি বা তার বেশি অ্যারে/হ্যাশ একসঙ্গে মার্জ করাও সম্ভব করে।
*) দিয়ে একটি অ্যারে কম্পোজ করাস্প্ল্যাট অপারেটর (*) দিয়ে একটি অ্যারে কম্পোজ করা যায়।
এটি সব মানকে একটি অ্যারেতে প্যাক করে।
>> fruits = ["apple", "banana", "cherry"]
>> more_fruits = ["orange", "kiwi", "melon", "mango"]
# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
>> combined_fruits = *fruits, *more_fruits
>> combined_fruits
=> ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
**) দিয়ে একটি হ্যাশ কম্পোজ করাডাবল স্প্ল্যাট অপারেটর (**) দিয়ে একটি হ্যাশ কম্পোজ করা হয়।
এটি একটি হ্যাশের সব কী (key)/মান জোড়া আরেকটি হ্যাশে প্যাক করে, বা দুটি হ্যাশ একসঙ্গে মিলিয়ে দেয়।
>> fruits_inventory = {apple: 6, banana: 2, cherry: 3}
>> more_fruits_inventory = {orange: 4, kiwi: 1, melon: 2, mango: 3}
# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}
# then the pairs are packed into combined_fruits_inventory
>> combined_fruits_inventory
=> {:apple=>6, :banana=>2, :cherry=>3, :orange=>4, :kiwi=>1, :melon=>2, :mango=>3}
*) ও ডাবল স্প্ল্যাট অপারেটর (**) ব্যবহারআপনি যখন এমন একটি মেথড তৈরি করেন যা যেকোনো সংখ্যক আর্গুমেন্ট নেয়, তখন মেথড ডেফিনিশনে *arguments বা **keyword_arguments ব্যবহার করতে পারেন।
*arguments দিয়ে যেকোনো সংখ্যক পজিশনাল (নন-কিওয়ার্ডেড) আর্গুমেন্ট প্যাক করা হয়, আর **keyword_arguments দিয়ে যেকোনো সংখ্যক কিওয়ার্ড আর্গুমেন্ট প্যাক করা হয়।
*arguments-এর ব্যবহার:
# This method is defined to take any number of positional arguments
# (Using the single line form of the definition of a method.)
>> def my_method(*arguments)= arguments
# Arguments given to the method are packed into an array
>> my_method(1, 2, 3)
=> [1, 2, 3]
>> my_method("Hello")
=> ["Hello"]
>> my_method(1, 2, 3, "Hello", "Mars")
=> [1, 2, 3, "Hello", "Mars"]
**keyword_arguments-এর ব্যবহার:
# This method is defined to take any number of keyword arguments
>> def my_method(**keyword_arguments)= keyword_arguments
# Arguments given to the method are packed into a dictionary
>> my_method(a: 1, b: 2, c: 3)
=> {:a => 1, :b => 2, :c => 3}
ডিফাইন করা মেথডে কিওয়ার্ড আর্গুমেন্টের জন্য কোনো প্যারামিটার (**keyword_arguments বা <key_word>: <value>) ডিফাইন করা না থাকলে, কিওয়ার্ড আর্গুমেন্টগুলো একটি হ্যাশে প্যাক হয়ে শেষ প্যারামিটারে অ্যাসাইন হবে।
>> def my_method(a)= a
>> my_method(a: 1, b: 2, c: 3)
=> {:a => 1, :b => 2, :c => 3}
*arguments ও **keyword_arguments একসঙ্গে মিলিয়েও ব্যবহার করা যায়:
def my_method(*arguments, **keyword_arguments)
p arguments.sum
for (key, value) in keyword_arguments.to_a
p key.to_s + " = " + value.to_s
end
end
my_method(1, 2, 3, a: 1, b: 2, c: 3)
6
"a = 1"
"b = 2"
"c = 3"
নির্দিষ্ট পজিশনাল আর্গুমেন্টের জন্য আপনি *arguments-এর আগে ও পরে আর্গুমেন্ট লিখতে পারেন।
এটি একটি অ্যারে ডিকম্পোজ করার মতোই কাজ করে।
আর্গুমেন্টগুলো একটি নির্দিষ্ট ক্রমে সাজাতে হবে:
def my_method(<positional_arguments>, *arguments, <positional_arguments>, <key-word_arguments>, **keyword_arguments)
এই ক্রম না মানলে আপনি একটি এরর পাবেন।
def my_method(a, b, *arguments)
p a
p b
p arguments
end
my_method(1, 2, 3, 4, 5)
1
2
[3, 4, 5]
আপনি *arguments-এর আগে ও পরে পজিশনাল আর্গুমেন্ট লিখতে পারেন:
>> def my_method(a, *middle, b)= middle
>> my_method(1, 2, 3, 4, 5)
=> [2, 3, 4]
আপনি পজিশনাল আর্গুমেন্ট, *arguments, কিওয়ার্ড আর্গুমেন্ট ও **keyword_arguments একসঙ্গেও মিলাতে পারেন:
>> def my_method(first, *many, last, a:, **keyword_arguments)
p first
p many
p last
p a
p keyword_arguments
end
>> my_method(1, 2, 3, 4, 5, a: 6, b: 7, c: 8)
1
[2, 3, 4]
5
6
{:b => 7, :c => 8}
ভুল ক্রমে আর্গুমেন্ট লিখলে একটি এরর হবে:
def my_method(a:, **keyword_arguments, first, *arguments, last)
arguments
end
my_method(1, 2, 3, 4, a: 5)
syntax error, unexpected local variable or method, expecting & or '&'
... my_method(a:, **keyword_arguments, first, *arguments, last)
মেথড কলে আর্গুমেন্টের একটি অ্যারে আনপ্যাক করতে আপনি স্প্ল্যাট অপারেটর (*) ব্যবহার করতে পারেন:
def my_method(a, b, c)
p c
p b
p a
end
numbers = [1, 2, 3]
my_method(*numbers)
3
2
1
মেথড কলে আর্গুমেন্টের একটি হ্যাশ আনপ্যাক করতেও আপনি ডাবল স্প্ল্যাট অপারেটর (**) ব্যবহার করতে পারেন:
def my_method(a:, b:, c:)
p c
p b
p a
end
numbers = {a: 1, b: 2, c: 3}
my_method(**numbers)
3
2
1