কালেকশনস (অ্যারে ও ডিকশনারী), ইনুম্যারেশন ও ক্লোজার

ভুমিকাঃ অ্যাপলের নতুন প্রোগ্রামিং ল্যাঙ্গুয়েজ সুইফ্ট নিয়ে লেখা আমাদের তৃতীয় সেকশনের প্রথম অধ্যায়ে সুইফ্ট সম্পর্কে পরিচিতি মুলক আলোচনা হয়েছে। আমরা সুইফ্ট ল্যাঙ্গুয়েজের বেসিক সিনট্যাক্স, ভ্যারিয়েবল ও কনস্ট্যান্ট ডিক্লেয়ার করা, বিভিন্ন ধরনের অপারেটর সম্পর্কে জেনেছি। দ্বিতীয় অধ্যায়ে স্ট্রিং ও ক্যারেকটার নিয়ে বিস্তারিত আলোচনা হয়েছে। এই অধ্যায়ে অ্যারে, ডিকশনারী ইত্যাদি কালেকশনস (Collections) ও অল্পবিস্তর ইনুম্যারেশন ও ক্লোজার নিয়ে আলোচনা হবে।

কালেকশন টাইপঃ ধরুন, আপনি একজন রেস্টুরেন্টের মালিক। আপনি আপনার রেগুলার কাস্টমারদের একটি তালিকা করতে চাচ্ছেন সুইফ্ট ল্যাঙ্গুয়েজে। একটু সহজ করার জন্য ধরে নিচ্ছি যে আপনি শুধু কাস্টমারদের নামের তালিকা করবেন। ভাবুন তো কিভাবে করবেন। যদি আপনার ১০০ জন কাস্টমার থাকে তাহলে ১০০ টা ভ্যারিয়েবল ডিক্লেয়ার করবেন। প্রত্যেকটিতে একজন করে কাস্টমারের নাম স্টোর করবেন।

var 1stCust = "First Customer's Name"
var 2ndCust = "2nd Customer's Name"
var 3rdCust = "3rd Customer's Name"
.
.
var 100thCust = "100th Customer's Name"

আচ্ছা, এবার বলুন তো আপনি যদি এই লিস্টটা দেখতে চান তাহলে কি করবেন?

println(1stCust)
println(2ndCust)
.
.
println(100thCust)

এভাবে করার সমস্যাটা হলঃ

  • আপনি নিশ্চয়ই জানেন না যে আপনার কাস্টমার সংখ্যা কত হতে পারে।
  • এভাবে ধরে ধরে এক-একটি ভ্যারিয়েবলে ডাটা স্টোর করতে হবে। আবার এক-একটি ধরে ডাটা ডিসপ্লে করতে হবে।
  • কোন রকমের সার্চিং টেকনিক (Searching Technique) অ্যাপ্লাই করা যাবে না। অর্থাৎ কোন নির্দিস্ট কাস্টমারের নাম খুজে বের করা যাবে না।
  • কোন রকমের সর্টিং টেকনিক (Sorting Technique) অ্যাপ্লাই করা যাবে না। অর্থাৎ লিস্টটিকে কোন নির্দিস্ট অর্ডারে সাজানো যাবে না।
এসব সমস্যার সমাধানের জন্য সুইফ্টে রয়েছে দুই ধরনের কালেকশন টাইপ (Collection Type) যথাঃ অ্যারে (Arrays) ও ডিকশনারী (Dictionaries)।

অ্যারে ও ডিকশনারী (Arrays and Dictionaries)ঃ একই ডাটাটাইপের অনেকগুলো ভ্যারিয়েবলের কালেকশনকেই অ্যারে অথবা ডিকশনারী বলা হয়। অ্যারে ও ডিকশনারী উভয়ই একটি নির্দিষ্ট ডাটাটাইপের এক বা একাধিক ডাটা সংরক্ষন করতে পারে। অ্যারেতে ভ্যালুগুলো সবসময় একটি অর্ডারে সাজানো থাকে। 0 থেকে শুরু করে 1, 2, 3, ..., n-1 পর্যন্ত অর্ডারে ডাটাগুলো থাকে। এই ০ থেকে n-1 কে অ্যারের ইনডেক্স বলা হয়। এখানে n মানে হল অ্যারের সাইজ বা অ্যারেতে থাকা ভ্যালুর সংখ্যা। এই ইনডেক্স ব্যবহার করেই অ্যারের ভ্যালু গুলো ম্যানিপুলেট করা হয়। অন্যদিকে ডিকশনারীতে ভ্যালুগুলো কোন নির্দিষ্ট অর্ডারে সাজানো থাকে না। এখানে ইনডেক্সকে বলা হয় কি (Key)। key হল নির্দিষ্ট ইউনিক আইডেন্টিফায়ার যা দিয়ে ডিকশনারীর ভ্যালুগুলোকে সংরক্ষন বা এক্সেস করা যায়। যেমন ঃ

restaurantArr[0] = 10; // Array
restaurantArr[1] = 15; // Array
restaurantDict["numberOfItem"] = 10  // Dictionary

অ্যারে (Array) একটি অ্যারেতে একই ডাটাটাইপের একাধিক ভ্যালু থাকতে পারে। ০ থেকে শুরু করে ১, ২, ৩, ... অর্ডারে সাজানো থাকে ভ্যালুগুলো। আবার একই ভ্যালু একাধিক বারও থাকতে পারে। অবজেকটিভ-সি এর NSArray এবং NSMutableArray তে যেকোন অবজেক্ট ভ্যালু হিসেবে রাখা যায়। এমনকি একটি অ্যারে তে বিভিন্ন টাইপের ভ্যালু বা অবজেক্ট থাকতে পারে। কিন্তু সুইফ্ট -এ অ্যারেতে একটি নির্দিষ্ট টাইপের ডাটা রাখা যাবে। উদাহরনস্বরুপ Int টাইপের অ্যারেতে শুধু Int টাইপের ডাটাই রাখা যাবে। অন্য কিছু না।

অ্যারে টাইপ ভ্যারিয়েবল ডিক্লেয়ার করাঃ বিভিন্নভাবে অ্যারে টাইপ ভ্যারিয়েবল ডিক্লেয়ার বা ইনিশিয়ালাইজ করা যায়। নিচে দুই ধরনের ডিক্লেয়ারেশন এর উদাহরন দেওয়া হলঃ

 ArrayvariableA
 var variableB: Int[] = [1, 2, 4]

উপরের কোডটিতে variableA এবং variableB নামের দুটি অ্যারে ডিক্লেয়ার করা হয়েছে। দুই ভাবেই অ্যারে ডিক্লেয়ার করা যায়। প্রথমটিকে ফুল ফর্ম আর দ্বিতীয়টিকে শর্টহ্যান্ড সিনট্যাক্স বলা হয়। শর্টহ্যান্ড সিনট্যাক্সই সবচেয়ে বেশী ব্যবহার করা হয়। এক্ষেত্রে var অথবা let লিখে তারপর অ্যারের নাম লিখতে হয়। এরপর কোলন (:) দিয়ে ডাটাটাইপ লিখে তারপর বন্ধনী ( [] ) চিহ্ন দিতে হয়।

অ্যারেতে সরাসরি [value1, value2,.....,valueN] অ্যাসাইন করে অ্যারে ইনিশিয়ালাইজ করা যায়। যেমনঃ

 var variableInt: Int[] = [12, 12, 34]
//variableInt is initialised with 12,12 and 34

 var variableString = ["Egg", "Fruits"]
// variableString is initialised with Egg and Fruits with these two string

সুইফ্ট এর টাইপ ইনফারেন্স (Type Inference) সুবিধার জন্য অ্যারে ডিক্লেয়ার বা ইনিশিয়ালাইজেশনের সময় অ্যারের টাইপ না লিখলেও অ্যাসাইন করা ভ্যালুর টাইপই হবে অ্যারে টাইপ। তাই variableString একটি String টাইপ অ্যারে কারন দুটি String টাইপের ভ্যালু দিয়ে অ্যারেটি ইনিশিয়ালাইজ করা হয়েছে।

অ্যারে ম্যানিপুলেশন (এক্সেস ও মডিফিকেশন) অ্যারের ভ্যালুগুলো পড়া (Access) বা আপডেট (Modification) করার জন্য সুইফ্ট ল্যাঙ্গুয়েজের অ্যারে টাইপ ভ্যারিয়েবলের জন্য কিছু প্রোপার্টি, মেথড আছে। এসব প্রোপার্টি বা মেথড দিয়ে অথবা সাবস্ক্রিপ্ট দিয়ে অ্যারে এক্সেস বা মডিফাই করা যায়। নিচে কিছু উদাহরন দিয়ে বিস্তারিত বর্ননা করা হলঃ কোন অ্যারেতে কতগুলো ভ্যালু আছে তা জানা যাবে রিড-অনলি প্রোপার্টি count দিয়ে।

var menuItems = ["Eggs", "Potatoes", Chilis"]
println("menuItems array has \(menuItems.count) items.") // menuItems array has 3 items.

প্রথমে menuItems অ্যারেটি ৩ টি স্ট্রিং টাইপ ভ্যালু দিয়ে ইনিশিয়ালাইজ করা হয়েছে। তারপর menuItems.count প্রোপার্টিতে অ্যারেতে কয়টি ভ্যালু আছে তা রিটার্ন করে। তাই menuItems.count ৩ রিটার্ন করবে।

বুলিয়ান isEmpty প্রোপার্টি দিয়ে কোন অ্যারে ফাঁকা কিনা তা চেক করা যায়। অর্থাৎ যদি কোন অ্যারের count ০ হয় বা অ্যারেতে কোন ইলিমেন্ট না থাকে তাহলে isEmpty প্রোপার্টি YES (true) রিটার্ন করে।

if menuItems.isEmpty {
    println("The menu list is empty.")
} else {
    println("The menu list is not empty.")
}
// prints "The menu list is not empty."

যেহেতু menuItems অ্যারেতে ৩টি স্ট্রিং ইলিমেন্ট আছে তাই menuItems.isEmpty প্রোপার্টি NO রিটার্ন করবে।

অ্যারের append মেথড ও += অপারেটর দিয়ে অ্যারেতে নতুন ভ্যালু যোগ করা যায়। আবার সরাসরি একটি নতুন অ্যারে কে += অপারেটর দিয়ে অ্যারের শেষে যোগ করা যায়। নিচে উদাহরন দেওয়া হলঃ

menuItems.append("Oils")
//Oils is appended on the menuItems array. Now menuItems has 4 strings.

menuItems += "Flour"
// Flour is appended on the menuItems array. Now menuItems has 5 strings

menuItems += ["Baking powder", "Butter", "Chocolate" ]
//An array of 3 new items is appended on the menuItems array. Now menuItems has 8 strings.

আগেই বলেছি অ্যারেতে ভ্যালুগুলো ০, ১, ২, ... অর্ডারে সাজানো থাকে। যেমন অ্যারের ৫ নম্বর ভ্যালু তথা ৫-১ বা ৪ তম ইনডেক্স এর ভ্যালু এক্সেস করার জন্য সাবস্ক্রিপ্ট সিনট্যাক্স ব্যবহার করে নিচের মত স্কয়ার ব্র্যাকেটের মধ্যে ইনডেক্স পাঠাতে হয়।

var 5thItem = menuItems[4]

এক্ষেত্রে অবশ্যই খেয়াল রাখতে হবে যাতে পাঠানো ইনডেক্সটি অ্যারেতে থাকা ভ্যালুর সংখ্যার সর্বোচ্চ ইনডেক্সের বেশী না হয়। ধরুন অ্যারেতে ০ থেকে ৪ ইনডেক্সে ৫ টি ভ্যালু রয়েছে। কিন্তু আপনি ৫ নম্বর ইনডেক্স তথা ৬ষ্ঠ ভ্যালু চাচ্ছেন। সেক্ষেত্রে "Array out of bound" টাইপের এরর হতে পারে।

একই ভাবে সাবস্ক্রিপ্ট সিনট্যাক্স দিয়ে কোন নির্দিষ্ট ইনডেক্স বা কোন রেন্জের মধ্যকার সকল ইনডেক্সের ভ্যালু আপডেট বা মডিফিকেশন করা যায়।

menuItems[4] = "Onion" // "Flour" is replaced by "Onion"
menuItems[1..3] = ["Bananas", "Apples"]
// Potatoes and Chilis are replaced by Bananas and Apples

এখানে, দ্বিতীয় উদাহরনটিতে 1..3 মানে 1 থেকে 3 রেন্জের (শেষ ইনডেক্স, এক্ষেত্রে ৩য় ইনডেক্স কন্সিডার হয় না) সকল ইনডেক্সের ভ্যালুকে একটি অ্যারে দিয়ে রিপ্লেস করা হচ্ছে যাতে দুটি ভ্যালু রয়েছে। অর্থাৎ সাবস্ক্রিপ্ট সিনট্যাক্স ব্যবহার করে যেকোন সংখ্যক ইনডেক্সের ভ্যালু অন্য যেকোন সংখ্যক ভ্যালু দিয়ে রিপ্লেস করা যাবে। উল্লেখযোগ্য কথা হল সাবস্ক্রিপ্ট সিনট্যাক্স (স্কয়ার ব্র্যাকেটের ভিতর অ্যারে ইনডেক্স পাঠানো) ব্যবহার করে অ্যারের ভ্যালু রিড করা বা নতুন ভ্যালু দিয়ে রিপ্লেস করা যায় ঠিকই কিন্তু নতুন কোন ভ্যালু অ্যারের শেষে ইনসার্ট (Add/ Append/ Insert) করা যায় না।

var recipes = ["Chicken Resala", "Mutton Curry"]
recipes[2] = "another recipe"   // Throws run time error because index 2 doesn't have value
println(recipes[2])      // Throws run time error because index 2 doesn't have value

recipes অ্যারেতে ০, ১ ইনডেক্সে মোট দুটি ভ্যালু রয়েছে। যদি ইনডেক্স ২ এর ভ্যালু এক্সেস করার বা নতুন ভ্যালু সেট করার চেষ্টা করা হয় তাহলে রান টাইম এরর হয়। অর্থাৎ সাকসেসফুল কম্পাইলেশনের পর কোড রান করলে যখনই মেশিন recipes অ্যারের ২ নম্বর ইনডেক্সের ভ্যালু এক্সেস করতে চাইবে তখনি এরর হবে কারন এই অ্যারেতে ২ নম্বর ইনডেক্স নেই।

কোন নির্দিষ্ট ইনডেক্সে নতুন ভ্যালু ইনসার্ট করার জন্য রয়েছে অ্যারের Insert মেথড। Insert মেথডে দুটি আরগুমেন্ট পাঠানো হয়। প্রথমে নতুন ভ্যালু ও তারপর যে ইনডেক্সে ইনসার্ট করতে হবে তার ভ্যালু।

menuItems.insert("Maple Syrup", atIndex: 2)

menuItems অ্যারের ২ নম্বর ইনডেক্সে Maple Syrup ইনসার্ট হয়ে গেছে। পরবর্তী সকল ভ্যালুর ইনডেক্স ১ করে বেড়ে গেছে। অর্থাৎ এই ইনসার্ট অপারেশন চালানোর পুর্বে যে ভ্যালুটি ইনডেক্স ২ তে ছিল এখন সেটি ইনডেক্স ৩ এ আছে।

নিচের মত করে removeAtIndex() মেথড দিয়ে অ্যারের যেকোন ইনডেক্সের ভ্যালু রিমুভ করা যায়। সেক্ষেত্রে রিমুভ করার পর ওই ইনডেক্সের পরবর্তী সকল ভ্যালুর ইনডেক্স ১ করে কমে যাবে।

menuItems.removeAtIndex(2)

ইনডেক্স ২ এর ভ্যালু রিমুভ হয়ে পরবর্তীতে থাকা সকল ভ্যালুর ইনডেক্স ১ করে কমে যাবে।

removeLast() মেথড দিয়ে সহজেই যেকোন অ্যারের শেষ ভ্যালুটি রিমুভ করা যায়। ফলে অ্যারের count ও ১ কমে যায়।

menuItems.removeLast() // removes the last element

for-in লুপ ব্যবহার করে অ্যারের সবগুলো ইনডেক্স ইটেরেট করা যায়। নিচের উদাহরনটি দেখা যাকঃ

 for item in menuItems
 {
    println(item)
 }

অ্যারে ইনিশিয়ালাইজেশনঃ শুরুতে কোন ভ্যালু ছাড়াই ফাঁকা অ্যারে ডিক্লেয়ার করার জন্য অ্যারের ডাটাটাইপ লিখে তারপর স্কয়ার ব্র্যাকেট লিখতে হয় নিচের মত করে।

var someInts = Int[]()
println("someInts is of type Int[] with \(someInts.count) items.")

সুইফ্ট এর Array তে রয়েছে এমন একটি ইনিশিয়ালাইজার যা দিয়ে একটি নির্দিষ্ট সাইজের অ্যারে ডিক্লেয়ার করা যাবে এবং প্রতিটি ইনডেক্সে একটি ডিফল্ট ভ্যালু সেট করা যাবে। উদাহরনস্বরুপ ধরুন আপনি চাচ্ছেন এমন একটি অ্যারে ডিক্লেয়ার করতে যার সাইজ (count) হবে ১০০ (ইনডেক্স 0 - 99) এবং প্রতিটি ইনডেক্সের ডিফল্ট ভ্যালু হবে 0.0 (repeatedValue)।

var hundredDoubles = Double[](count: 100, repeatedValue: 0.0)
// hundredDoubles is of type Double[], and equals [0.0, 0.0, 0.0, ...]

hundredDoubles অ্যারেটি ডিক্লেয়ার করার সময় ব্র্যাকেটের মধ্যে দুটি আর্গুমেন্ট পাঠানো হয়। প্রথমটি count যা অ্যারের সাইজ কত হবে তা ডিফাইন করে। দ্বিতীয়টি repeatedValue যা অ্যারের সকল ইনডেক্সের ডিফল্ট ভ্যালু কত হবে তা সেট করে। আবার Double[] লিখে অ্যারের ভ্যালুগুলোর ডাটাটাইপ কি হবে তাও বলে দেওয়া হয়েছে। সুইফ্ট এর টাইপ ইনফারেন্স সুবিধার জন্য ডাটাটাইপ না বলে দিয়ে নিচের মত করে অ্যারে ইনিশিয়ালাইজ করা যায়।

var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]

একথা বলাই বাহুল্য যে দুটি অ্যারে কে "+" অপারেটর দিয়ে যোগ করলে প্রথম অ্যারের শেষে দ্বিতীয় অ্যারেটি অ্যাপেন্ড হয়।

var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

ডিকশনারী (Dictionaries) ঃ অ্যারের মতই ডিকশনারীতে একই টাইপের একাধিক ভ্যালু স্টোর করা যায়। প্রত্যেকটি ভ্যালুর জন্য একটি করে ইউনিক কি (key) বা আইডেন্টিফায়ার থাকে। অ্যারেতে ০ থেকে শুরু করে ১, ২, ৩, ... ইনডেক্স গুলোতে ভ্যালু গুলো থাকে কিন্তু ডিকশনারীতে ভ্যালুগুলো অ্যারের মত ইনডেক্সিং করে সাজানো থাকে না। ঠিক বাস্তব ডিকশনারী তে যেমন নির্দিষ্ট শব্দের জন্য নির্দিষ্ট সংজ্ঞা থাকে তেমনি সুইফ্ট এর ডিকশনারীতে প্রত্যেকটি ভ্যালু নিজের ইউনিক আইডেন্টিফায়ার দিয়ে স্টোর করা থাকে। এই আইডেন্টিফায়ার বা ভ্যালু উভয়টি যেকোন টাইপের হতে পারে। তবে একটি ডিকশনারীর সকল ভ্যালুর টাইপ একই হবে এবং সকল আইডেন্টিফায়ারের টাইপ একই হবে।

অবজেকটিভ-সি এর NSDictionary ও NSMutableDictionary তে একই ডিকশনারীতে বিভিন্ন টাইপের ভ্যালু বা আইডেন্টিফায়ার (key) থাকতে পারে। ফলে ডিকশনারীর টাইপ নির্দিষ্ট থাকে না। অন্যদিকে যেহেতু সুইফ্টের ডিকশনারীর সকল ইলিমেন্ট এর টাইপ একই হয় তাই ডিকশনারীর ভ্যালুর টাইপ সম্পর্কে নিশ্চিন্ত থাকা যায়।

ডিকশনারী (Dictionaries) ডিক্লেয়ারেশন ঃ সুইফ্টে ডিকশনারী টাইপ ডিক্লেয়ার করার জন্য Dictionary লিখতে হয়। এখানে KeyType হল সেই আইডেন্টিফায়ার বা কি (key) এর টাইপ এবং ValueType হল ডিকশনারীতে স্টোর করা ভ্যালুর টাইপ। যেমনঃ

var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"]

ডিকশনারী ইনিশিয়ালাইজ করার জন্য অ্যারের মতই শর্টহ্যান্ড সিনট্যাক্স ব্যবহার করা হয়। অর্থাৎ ভ্যারিয়েবল ডিক্লেয়ার করার সময় স্কয়ার ব্র্যাকেটের ভিতর ভ্যালুগুলো লিখে দেওয়া। কিন্তু ডিকশনারী তে যেহেতু অ্যারের মত ইনডেক্সিং হয় না, তাই এখানে কি-ভ্যালু পেয়ার (key-value pairs) দিয়ে ডিকশনারী ইনিশিয়ালাইজ করতে হয়। উপরের উদাহরনটিতে ডিকশনারীর ইলিমেন্টগুলো কমা (,) দিয়ে লেখা হয়েছে। এবং প্রত্যেক ইলিমেন্ট এর কোলন (:) দিয়ে কি-ভ্যালু পেয়ার লেখা হয়েছে। এখানে কোলনের ডানদিকের অংশটি হল ভ্যালু ও বামদিকের অংশটি হল এই ভ্যালুর জন্য ইউনিক আইডেন্টিফায়ার বা কি (key)।

নোট ঃ আমরা বার বার বলছি যে ডিকশনারীর কি (key) গুলো অবশ্যই ইউনিক হতে হবে। তা না হলে একই কি(key) এর জন্য যদি একাধিক ভ্যালু স্টোর করা হয় তাহলে তা Ambiguity তৈরী করবে। এজন্যই সুইফ্টে কি(key) এর জন্য এমন ডাটাটাইপ ব্যবহার করতে হবে যেগুলোকে হ্যাশ করা যায়। String, Int, Double, Bool ইত্যাদি ডাটাটাইপ বাই-ডিফল্ট হ্যাশ করা যায়। তাই এসবগুলো ডাটাটাইপই ডিকশনারীর কি(key) হিসেবে ব্যবহার করা যাবে।

ডিকশনারী ম্যানিপুলেশন (এক্সেস ও মডিফিকেশন)ঃ ডিকশনারীর ভ্যালুগুলো পড়া (Access) বা আপডেট (Modification) করার জন্য সুইফ্ট ল্যাঙ্গুয়েজের ডিকশনারী টাইপ ভ্যারিয়েবলের জন্য আছে কিছু প্রোপার্টি, মেথড। এসব প্রোপার্টি বা মেথড দিয়ে অথবা সাবস্ক্রিপ্ট দিয়ে ডিকশনারী এক্সেস বা মডিফাই করা যায়। নিচে কিছু উদাহরন দিয়ে বিস্তারিত বর্ননা করা হলঃ

কোন ডিকশনারীতে কতগুলো ভ্যালু আছে তা জানা যাবে রিড-অনলি প্রোপার্টি count দিয়ে।

var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"]
println("airports array has \(menuItems.count) items.") // airports dictionary has 2 items.

প্রথমে airports ডিকশনারীটি 2 টি স্ট্রিং টাইপ ভ্যালু দিয়ে ইনিশিয়ালাইজ করা হয়েছে যাদের কি-ভ্যালু পেয়ার হল String : String। তারপর airports.count প্রোপার্টিতে ডিকশনারীতে কয়টি ভ্যালু আছে তা রিটার্ন করে। তাই airports.count 2 রিটার্ন করবে।

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

airports["LHR"] = "London"  // new item with "LHR" : "London" key-pair is inserted
// the airports dictionary now contains 3 items

airports["LHR"] = "London Heathrow" // existing item of key "LHR" is updated by ""London Heathrow""
// the value for "LHR" has been changed to "London Heathrow"

সাবস্ক্রিপ্ট সিনট্যাক্স ব্যবহার না করে ডিকশনারীর updateValue(forKey:) মেথড দিয়ে কোন নির্দিষ্ট কি (key) এর ভ্যালু আপডেট করা যায় আবার নতুন কি-পেয়ার ভ্যালু ইনসার্ট করা যায়।

if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
    println("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin."

উপরের কোডটিতে দেখা যাচ্ছে updateValue মেথডে দুটি আর্গুমেন্ট পাঠানো হচ্ছে। প্রথমটিতে ভ্যালু এবং দ্বিতীয়টিতে কি(key)। এখানে ভ্যালু হিসেবে "Dublin International" এবং forKey:"DUB" এ কি (key) হিসেবে "DUB" পাঠানো হচ্ছে। প্রথমে চেক করা হচ্ছে যে DUB কি দিয়ে কোন ইলিমেন্ট ডিকশনারীতে আছে কিনা। যেহেতু airports ডিকশনারীতে এই কি দিয়ে একটি ভ্যালু আছে তাই এই কি এর পুর্বের ভ্যালুটি নতুন পাঠানো Dublin International দিয়ে আপডেট হয়ে গেছে এবং পুর্বের ভ্যালুটি রিটার্ন করে যা oldValue ভ্যারিয়েবলে অ্যাসাইন হয়। যদি airports ডিকশনারীতে এই কি দিয়ে কোন ভ্যালু না থাকত, তাহলে নতুন ইলিমেন্ট হিসেবে "DUB" : "Dublin International" কি-পেয়ার ডিকশনারীতে যুক্ত হত।

সাবস্ক্রিপ্ট সিনট্যাক্সে স্কয়ার ব্র্যাকেটের মধ্যে কি(key) লিখে ওই কি এর ভ্যালু রিড বা এক্সেস করা যায়।

var airport = airports["DUB"]
println(airport) // Dublin International

কোন নির্দিষ্ট কি এর ভ্যালু রিমুভ করতে চাইলে তার সাবস্ক্রিপ্ট এ nil অ্যাসাইন করলেই তা ডিকশনারী থেকে রিমুভ হয়ে যাবে।

  airports["DHK"] = "Shahjalal International Airport"
// airports contains 3 items right now.

  airports["DHK"] = nil
// Value for "DHK" key is removed from airports and this dictionary contains two items

আবার সাবস্ক্রিপ্ট ব্যবহার না করে removeValueForKey() মেথড দিয়ে কোন নির্দিষ্ট কি-ভ্যালু পেয়ার ডিকশনারী থেকে রিমুভ করা যায়। এক্ষেত্রে মেথডটি রিমুভ হওয়া ভ্যালুটি রিটার্ন করে।

if let removedValue = airports.removeValueForKey("DUB") {
    println("The removed airport's name is \(removedValue).")
} else {
    println("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin International."

অ্যারের মতই for-in লুপ দিয়ে ডিকশনারীতে থাকা সকল ভ্যালুতে ইটেরেট করা যায়। ডিকশনারী তে কি-ভ্যালু পেয়ার হিসেবে ভ্যালু থাকে তাই এখানে অ্যারের মতই একই সাথে কি এবং ভ্যালু এক্সেস করা যায়।

for (airportCode, airportName) in airports {
    println("\(airportCode): \(airportName)")
}
// TYO: Tokyo
// LHR: London Heathrow

আবার চাইলে শুধু keys অথবা শুধু values প্রোপার্টি ইটেরেট করে শুধু কি বা শুধু ভ্যালুগুলো এক্সেস করা যায়।

for airportCode in airports.keys {
    println("Airport code: \(airportCode)")
}
// Airport code: TYO
// Airport code: LHR

for airportName in airports.values {
    println("Airport name: \(airportName)")
}
// Airport name: Tokyo
// Airport name: London Heathrow

একটি ফাঁকা ডিকশনারী (Empty Dictionary) ইনিশিয়ালাইজ করা ঃ ইনিশিয়ালাইজার সিনট্যাক্স ব্যবহার করে অ্যারের মতই ফাকা ডিকশনারী ইনিশিয়ালাইজ করা যায়।

var namesOfIntegers = Dictionary()
// namesOfIntegers is an empty Dictionary

উদাহরনটিতে nameofIntegers নামের একটি ডিকশনারী ইনিশিয়ালাইজ করা হয়েছে যার কি গুলো Integer টাইপ, কিন্তু ভ্যালুগুলো হবে String টাইপ।

কোন ডিকশনারী ইনিশিয়ালাইজ করার সময় যদি টাইপ বলে দেওয়া হয় অথবা কোন ভ্যালু ইনিশিয়ালাইজ করার ফলে টাইপ ইনফারেন্স ঘটে তাহলে ডিকশনারী টি ফাঁকা করলেও টাইপ পরিবর্তন হয় না। এই বৈশিষ্ট্য অ্যারের ক্ষেত্রেও প্রযোজ্য।

namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type Int, String

কোন ডিকশনারী তে [:] এভাবে স্কয়ার ব্র্যাকেটের ভিতর শুধু কোলন (:) দিয়ে অ্যাসাইন করলে তা ফাকা ডিকশনারীতে পরিনত হয়।

ইনুম্যারেশন ও ক্লোজার (Enumerations and Closures) ঃ ইনুম্যারেশন দিয়ে একই ধরনের একগুচ্ছ ভ্যালু টাইপকে প্রকাশ করা হয়। আপনি যদি সি/সি++ এর সাথে পরিচিত থাকেন তাহলে নিশ্চয়ই জানেন যে, সি তে একটি এনাম (enum) টাইপ গ্রুপের সকল ভ্যারিয়েবলকে ইনটিজার(Integer) ভ্যালু দিয়ে অ্যাসাইন করা হয়। সুইফ্ট এ ইনুম্যারেশন অনেক বেশী ফ্লেক্সিবল এবং সি এর মত গ্রুপের ভ্যালুগুলো শুধু ইনটিজার ভ্যালু হয় না। যেকোন ডাটাটাইপ যেমন String, Character, Integer বা Float টাইপ হতে পারে।

enum CompassPoint {
    case North
    case South
    case East
    case West
}

সব ল্যাঙ্গুয়েজেই enum কিওয়ার্ড দিয়ে ইনুম্যারেশন টাইপ ডিক্লেয়ার করা হয়। উপরের উদাহরনটিতে CompassPoint নামে একটি enum টাইপ ডিক্লেয়ার করা হয়েছে যার চারটি সদস্য (member) যথাক্রমে North, South, East এবং West রয়েছে। সি/সি++ বা অন্য যেকোন ল্যাঙ্গুয়েজে enum টাইপের প্রত্যেকটি সদস্য (member) এ ০ থেকে ১, ২, ৩, ... integer ভ্যালু অ্যাসাইন হয়। কিন্তু সুইফ্ট এর enum টাইপ এর member দের ভ্যালুতে এরকম কোন ডিফল্ট ভ্যালু অ্যাসাইন করা হয় না।

কোন নির্দিষ্ট ফাংশনালিটি সহ একটি কোড ব্লককে ক্লোজার (Closure) বলা হয় ({ })। সুইফ্টের ক্লোজার ঠিক অবজেকটিভ-সি এর ব্লক (Block) এর মতই কাজ করে। নিচে ক্লোজারের একটি জেনারেল ফর্ম লেখা হল।

{ (param: Type) -> ReturnType in
    expression_using_params
}

উপরের "->" চিহ্নটি আর্গুমেন্ট ও রিটার্ন টাইপকে আলাদা করে এবং "in" ক্লোজার এর হেডার থেকে ক্লোজার এর বডি আলাদা করে। নিচে একটি উদাহরণ,

var numbers = [1, 2, 3, 4, 5]
numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
    })

যদি টাইপ জানা থাকে (যেমন উপরে), তাহলে নিচের মত করেও এই ক্লোজারটি ব্যবহার করা যেতে পারে,

var numbers = [1, 2, 6]
numbers = numbers.map({ number in 3 * number })
println(numbers) // [3, 6, 18]

পরিসমাপ্তিঃ এ অধ্যায়ে কালেকশন টাইপ নিয়ে বিস্তারিত আলোচনা হয়েছে। আমরা দেখেছি কিভাবে অ্যারে ও ডিকশনারী ইনিশিয়ালাইজ করা ও ম্যানিপুলেট করতে হয়। এছাড়া জেনেছি অ্যারে ও ডিকশনারীর মধ্যকার পার্থক্য ও সুবিধা-অসুবিধা। এছাড়া ইনুম্যারেশন ও ক্লোজার সম্পর্কে নামমাত্র আলোচনা হয়েছে। এ অধ্যায় সম্পর্কিত আরও বিস্তারিত থাকবে আমাদের কাগুজে বইয়ে।

বইয়ের আপডেট পেতে চোখ রাখুন আমাদের ফ্যান পেজে

Originally Posted Here