শার্প সমাচার (১) : লিংক নিয়ে প্রাথমিক আলোচনা

না, এই লিংক মানে সেই বিখ্যাত (!) link না।

এ কেমন লিংক!

এই লিংকের মানে হচ্ছে LINQ, অর্থাৎ Language Integrated Query। এটার কাজ হচ্ছে কোন অবজেক্টের একটা আইটারেবল কালেকশন থেকে bool টাইপের এক্সপ্রেশন দিয়ে (কিংবা bool টাইপ রিটার্ন করে এমন ল্যাম্বডা এক্সপ্রেশন দিয়ে) প্রকাশ করা একটা নির্দিষ্ট শর্ত মেনে চলে, এ ধরনের অবজেক্টগুলোকে বের করা, এবং/অথবা অবজেক্টগুলোকে একটা নির্দিষ্ট property দিয়ে sort করা।

এখানে অনেকগুলো কঠিন কঠিন কথা বলে ফেললাম। আইটারেবল কালেকশন, ল্যাম্বডা এক্সপ্রেশন, এসবের আসলে মানে কী?

এসবের মানে-টা কী?!

আচ্ছা, একে একে ব্যাখ্যা করা যাক।

  • আইটারেবল (Iterable) কালেকশন হচ্ছে কিছু অবজেক্টের একটা সমষ্টি যেটাকে enumerate করা যায়, অর্থাৎ যেটার মধ্যে শুরু থেকে শেষ পর্যন্ত প্রতিটি অবজেক্ট সিরিয়াল নাম্বার ধরে ধরে পাওয়া যায়। এর সবচেয়ে ভালো উদাহরণ হতে পারে একটা ইন্টিজারের অ্যারে। এখানে ইন্টিজারের অ্যারে-টা হচ্ছে একটা আইটারেবল অবজেক্ট, যেখানে প্রতিটি মেম্বার অবজেক্টকে, অর্থাৎ ইন্টিজারকে, 0 থেকে শুরু করে (length - 1) পর্যন্ত ধরে ধরে access করা যায়। এ ধরনের টাইপের আরও উদাহরণ অ্যারে, লিংকড-লিস্ট, লিস্ট, স্ট্যাক, কিউ ইত্যাদি। ডটনেটে এ ধরনের টাইপগুলো IEnumerable ইন্টারফেসকে ইমপ্লিমেন্ট করে। এই ইন্টারফেসকে ইমপ্লিমেন্ট করার জন্য যে কাজগুলো করতে হয়, সেগুলোর মাধ্যমেই টাইপগুলো আইটারেবল হয়ে ওঠে।
  • ল্যাম্বডা এক্সপ্রেশন হচ্ছে একটা ফাংশন বা মেথডকে সহজে ও ছোট করে লেখার একটা কায়দা। এর জন্য প্রথমে প্যারামিটারগুলোকে লিখতে হবে, তারপর ল্যাম্বডা এক্সপ্রেশন “=>” দিতে হবে (এটাকে সি-শার্প ল্যাঙ্গুয়েজের জনকের নামানুসারে “হেইলসবার্গ অপারেটর”ও বলা হয়)। এরপর ফাংশনের বডি লিখতে হবে। ছোটখাট ফাংশন হলে সরাসরি কী return করতে হবে বলে দিলেই চলে। আর একটু বড় ডেফিনিশনের জন্য curly braces-এর মধ্যে লিখতে হবে। একটা উদাহরণ দেওয়া যাক:
static void Main(string[] args)
{
    Func<int,> SumOf = (a, b) => a + b;
    Console.WriteLine($"Sum of 10 and 15 is {SumOf(10, 15)}");
    // Console output:
    // Sum of 10 and 15 is 25
}

দেখা যাচ্ছে, ল্যাম্বডা এক্সপ্রেশনকে ডিক্লেয়ার করার জন্য Func<int,> লেখা হয়েছে। প্রথম দুটো int দিয়ে বোঝানো হচ্ছে, ল্যাম্বডা এক্সপ্রেশনটা দুটো int টাইপের আর্গুমেন্ট নেয়। পরেরটা দিয়ে বোঝানো হচ্ছে, এখান থেকে int রিটার্ন দেওয়া হয়।

যাক, এতক্ষণ তো দুটো বিষয় পরিষ্কার হওয়া গেলো। এবার মূল আলোচনায় ফেরা যাক। সেটা হচ্ছে, লিংক দিয়ে কী কী কাজ করা সম্ভব।

১. ডেটা খুঁজে বের করা বা query করা

লিংক দিয়ে একটা আইটারেবল কালেকশনের মধ্যে ডেটা কুয়েরি করা একেবারেই সহজ। সিনট্যাক্সটা হচ্ছে দুই রকম: Query syntax, আর Method syntax।

কুয়েরি সিনট্যাক্স অনেকটা SQL-এর সিনট্যাক্সের মতই:

IEnumerable<type> results = from x in MyListOfThings
where CheckSomething(x)
orderby x.SomeAttribute
select x;

আর মেথড সিনট্যাক্সে ল্যাম্বডা এক্সপ্রেশন ব্যবহার করতে হয়:

IEnumerable<type> results = MyListOfThings
.Where(x => CheckSomething(x))
.Orderby(x => x.SomeAttribute);

দেখা যাচ্ছে, মেথড সিনট্যাক্সে কুয়েরির জন্য ল্যাম্বডা এক্সপ্রেশনগুলোকে Func<t,> টাইপের এবং সর্টিংয়ের জন্য Func<t,> টাইপের হতে হবে। এখানে T হচ্ছে যে টাইপের ডেটার কালেকশনের মধ্যে খোঁজাখুঁজি করা হচ্ছে, সেই টাইপ। আর TKey হচ্ছে সেই টাইপের যেকোন একটা property।

যাক, তাহলে বিষয়টা পরিষ্কার হয়ে গেলো…

কী বললেন?

রিয়েল লাইফ উদাহরণ

বেশ!

ধরা যাক, আপনার স্কুলে শিক্ষার্থীদের তথ্য সংরক্ষণের জন্যে একটা প্রোগ্রাম লিখেছেন। সে প্রোগ্রামের জন্য স্টুডেন্ট ক্লাসের ডেফিনিশন লিখেছেন এভাবে:

public class Student
{
    public int ID { get; private set; }
    public string Name { get; private set; }

    private int _score;
    public int Score
    {
        get => _score;
        set => _score = (value >= 0 && value <=> AtLeast80 = new List<student>();
foreach (Student s in class_V)
{
    if (s.Score >= 80)
        AtLeast80.Add(s);
}

ঠিক আছে, তাহলে লুপ চালিয়ে কাজটা করতে হবে। কিন্তু এই কাজটা কি আরও সহজে করা যায়?

দেখা যাক, লিংক দিয়ে একই কাজ কীভাবে করা যায়:

// Query syntax
List<student> AtLeast80 = (from s in class_V
where s.Score >= 80
select s).ToList();

কুয়েরি সিনট্যাক্স ব্যবহার করায় বেশ ছোট হয়ে এসেছে কোড।

List<student> AtLeast80 = class_V.Where(s => s.Score >= 80).ToList();

মেথড সিনট্যাক্সের ক্ষেত্রে আরও অল্প কোড লিখতে হয়েছে, ল্যাম্বডা এক্সপ্রেশন ব্যবহারের সুবাদে।

বলে রাখা প্রয়োজন, লিংক স্টেটমেন্ট সব সময় IEnumerable<t> টাইপ রিটার্ন করে। এ কারণে সেটাকে List<t> টাইপে কনভার্ট করার জন্য .ToList() অংশটুকু যোগ করা হয়েছে (বলা বাহুল্য, আমাদের এই উদাহরণে T হচ্ছে Student টাইপ)। স্টুডেন্টের লিস্টের পরিবর্তে স্টুডেন্টের অ্যারে পেতে চাইলে .ToArray() মেথড যোগ করে দিলেই চলবে।

২. ডেটাকে বিন্যস্ত করা বা sort করা

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

ধরা যাক, পরীক্ষায় ৮০ বা তার বেশি স্কোর পাওয়া শিক্ষার্থীদের এই লিস্টটাকে আপনি স্কোরের অধঃক্রমানুসারে, অর্থাৎ in descending order, সাজিয়ে দেখাতে হবে। তো আপনি খুশি মনে আপনার জানা অ্যালগরিদম ইমপ্লিমেন্ট করতে লেগে গেলেন।

ধরে নিচ্ছি, আপনার পছন্দের সর্টিং অ্যালগরিদম হচ্ছে কুইক সর্ট।

static void QuickSort(List<student> students, int left, int right)
{
    if (left < right)
    {
        int mid = Partition(students, left, right);

        if (mid > 1)
        // then sort left part
            QuickSort(students, left, mid - 1);
        if (mid + 1 < right)
        // then sort right part
            QuickSort(students, mid + 1, right);
    }
}

static int Partition(List<student> students, int left, int right)
{
    int pivot = students[left].Score; // choosing a point of pivot

    while (true)
    {
        while (students[left].Score > pivot)
            left++;
        while (students[right].Score < pivot)
            right--;

        if (left < right)
        // then swap
        {
            Student temp = students[right];
            students[right] = students[left];
            students[left] = temp;
        }
        else
        // no need to swap, just return the index of the last item
            return right;
    }
}

বেশ বড়সড় একটা কোড দেখা যাচ্ছে। এই দুটো মেথড লেখার পর QuickSort(AtLeast80, 0, AtLeast80.Count - 1) কল করলেই কাজ হয়ে যাবে।

এবার দেখা যাক, লিংক ব্যবহার করে কাজটা কীভাবে করা যেতে পারে:

var myList = (from s in AtLeast80
orderby s.Score descending
select s).ToList();

কুয়েরি সিনট্যাক্স। একদম মন্দ না, কী বলেন?

আর যদি মেথড সিনট্যাক্স ব্যবহার করি?

var myList = AtLeast80.OrderByDescending(s => s.Score).ToList();

মেথড সিনট্যাক্স — এক লাইনেই শেষ!

অবাক কোয়ালা

যাক, আশা করি এটুকু আলোচনা থেকে লিংকের খুঁটিনাটি বোঝা না গেলেও অন্তত এটুকু বোঝা গেলো, লিংক দিয়ে অনেক বিশাল বিশাল কাজ অল্প কোড দিয়েই করে ফেলা সম্ভব।

আজকের মতো সি-শার্প বিষয়ক আলোচনা এটুকুই থাক 😊


কৃতজ্ঞতা স্বীকার: কুইকসর্ট অ্যালগোরিদমের জন্য C# Corner ওয়েবসাইটের সাহায্য নিয়েছি। মিমগুলো Imgflip ওয়েবসাইটে বানানো।</student></student></t></t></student></student></student></=></t,></t,></type></type></int,></int,>