اپراتورهای Projection در LINQ

12 فروردین 1398
درسنامه درس 2 از سری آموزش LINQ
LINQ-projection-operators

سلام با بخش دوم آموزش Linq در C# در خدمت شما عزیزان هستیم. در این جلسه قصد داریم با Projection Operators in LINQ در زبان C# آشنا شویم.

اپراتورهای Projection‌ چیست؟

در زبان C# دو نوع Projection Operators وجود دارد:

  • Select
  • Select many
شرح عملکرد نوع اپراتور
با استفاده از این متد می توان محتویات یک منبع داده را واکشی (دریافت) کرد. select
با استفاده از این متد می توان اطلاعات را از داخل یک مجموعه به صورت یک مجموعه ای دیگر واکشی کرد. SelectMany

متد select

برای انتخاب داده ها از یک مجموعه استفاده می شود و کاربرد آن دقیقا مانند select در زبان Sql است.

روش کلی استفاده از آن به صورت زیر می باشد.

var result = from u in userslist
select u;

در واقع userslist می تواند هر نوع منبع داده ای باشد که در ادامه در مورد هر کدام بحث خواهد شد. نوع متغییر result بسته به نوع داده ی مورد استفاده می تواند از نوع  <>IEnumerable یا <>IQueryable باشد که در بخش های بعدی آموزش مورد بررسی قرار می گیرد؛ فعلا می توانید به جای آن ها از نوع داده ی var استفاده کنید.

برای درک کاربرد select به مثال های زیر توجه کنید.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Linqtutorials
{
    class MainClass
    {
        static void Main(string[] args)
        {
            List<Student> stuList = new List<Student>()
            {
                new Student(){ ID=100,Name="amir",Age=23,Average=16.25},
                new Student(){ ID=101,Name="reza",Age=22,Average=12.3},
                new Student(){ ID=102,Name="sara",Age=22,Average=12},
                new Student(){ ID=103,Name="hassan",Age=24,Average=18},
                new Student(){ ID=104,Name="mina",Age=21,Average=17.11},
            };
            var StudentList = from stu in stuList
                              select stu;
            Console.WriteLine("name" + "\t" + "average");
            foreach (Student item in StudentList)
            {
                Console.WriteLine("{0}"+"\t"+"{1}",item.Name,item.Average);
            }
            Console.ReadKey();
        }
    }
    public class Student
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public double Average { get; set; }
    }
}

در این مثال یک کلاس Student ایجاد و در متد main یک لیست را با نوع داده ی کلاس Student پر کرده ایم. با استفاده از دستور select، اطلاعات از داخل آن واکشی شده است و در آخر با استفاده از یک حلقه مقادیر آن در خروجی نمایش داده می شود. توجه داشته باشید که تمامی فیلد های کلاس Student توسط متغیر item قابل دسترسی هستند.

حالا موس را بر روی StudentList نگه دارید تا نوع آن نمایان شود، مشاهده می کنید که نوع آن <IEnumerable<Student است.

در مثال بالا نحوه ی واکشی اطلاعات تا حدودی شبیه به Sql بود اما این مثال به صورت زیر نیز قابل پیاده سازی است که کافیست قسمت

var StudentList = from stu in stuList
select stu;

به

 var StudentList = stuList.Select(x => x);

تغییر داده شود، سپس خروحی را دوباره مشاهده کنید خواهید دید که هیچ تفاوتی ندارند.

خروجی مثال اول متد Select
خروجی مثال اول متد Select

به مثال دیگری از کاربرد select توجه کنید.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Linqtutorials
{
    class MainClass
    {
        static void Main(string[] args)
        {
            double[] fnum = { 12.3, 11.5, 18.5, 101.2, 77.5 };
              var number = from s in fnum
                select s;
            foreach (double item in number)
            {
                Console.WriteLine("Num is : {0}",item);
            }
            Console.ReadKey();
        }
    }  
}

در این مثال ساده یک آرایه از نوع double تعریف و برای آن اعضایی در نظر گرفته شده است، سپس با استفاده از select تمامی اعضای آن در متغیر number قرار گرفته اند و با استفاده از یک حلقه تمامی مقادیر قابل پیمایش هستند.

با قرار دادن موس بر روی متغیر number می توانید نوع آن را مشاهده کنید.

مثال بالا به شکل زیر نیز قابل تغییر است.

var number = fnum.Select(f => f);

توجه کنید نام انتخابی برای متغیر Lambda Expressions در داخل متد select دلخواه بوده که در این دو مثال x و f در نظر گرفته شده است.

خروجی مثال دوم متد Select
خروجی مثال دوم متد Select

در این دو مثال تا حدودی با کاربرد select در LINQ آشنا شدید که هر دو مثال جز دسته بندی  Linq To Object  قرار داشتند. در ادامه به بررسی کاربرد متد SelectMany خواهیم پرداخت.

متد SelectMany

کاربرد این متد زمانی است که می خواهیم مجموعه ای از داده را از دل یک مجموعه ی دیگر واکشی کنیم. استفاده از این متد باعث کاهش خطوط برنامه و پیچیدگی می شود که در نتیجه ی آن کدها به صورت بهینه نوشته خواهند شد.

به مثال زیر توجه کنید.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Linqtutorials
{
    class MainClass
    {
        static void Main(string[] args)
        {
            List<Student> Objstudent = new List<Student>()
            {
                new Student() { Name = "Ravi Varma", Gender = "Male", Subjects = new List<string> { "Mathematics", "Physics" } },

                new Student() { Name = "Vikram Sharma", Gender = "Male", Subjects = new List<string> { "Social Studies", "Chemistry" } },

                new Student() { Name = "Harish Dutt", Gender = "Male", Subjects = new List<string> { "Biology", "History", "Geography" } },

                new Student() { Name = "Akansha Wadhwani", Gender = "Female", Subjects = new List<string> { "English", "Zoology", "Botany" } },

                new Student() { Name = "Vikrant Seth", Gender = "Male", Subjects = new List<string> { "Civics", "Drawing" } }
            };
            var Subjects = Objstudent.SelectMany(x => x.Subjects);
            foreach (string Subject in Subjects)
            {
                Console.WriteLine(Subject);
            }

            Console.ReadLine();
        }
    }
    class Student
    {
        public string Name { get; set; }

        public string Gender { get; set; }

        public List<string> Subjects { get; set; }
    }
}

همان طور که مشاهده می  کنید، در کلاس Student یک فیلد از جنس List قرار دارد و در کلاس main در داخل یک List با نوع داده ی Student چند شی از آن ایجاد کرده ایم. در این مثال قصد داریم مجموعه داده ای (Subjects) را از داخل یک List دیگر استخراج کنیم. کد را اجرا و خروجی را مشاهده کنید.

حالا سعی کنید همین مثال را با استفاده از Select بازنویسی کنید؛ پس SelectMany را به Select تغییر دهید و موس را بر روی متغیر Subjects قرار دهید و نوع داده را مشاهده کنید، خواهید دید که نوع آن <<IEnumerable<List<string است در صوتی که هنگام استفاده از SelectMany نوع آن به صورت <IEnumerable<string بود. برای اجرا شدن برنامه با استفاده از متد Select باید کد را به صورت زیر تغییر دهید. در ضمن باقی قسمت ها نیاز به تغییر ندارند:

 IEnumerable<List<string>> Subjects = Objstudent.Select(x => x.Subjects);
            foreach (List<string> Subject in Subjects)
            {
                foreach (string s in Subject)
                {
                    Console.WriteLine(s);

                }
            }

به وضوح مشخص است که چگونه متد SelectMany از خطوط برنامه و پیچیدگی آن می کاهد.

حال این مثال را به صورت Query بازنویسی می کنیم که به صورت زیر خواهد بود. توجه کنید که باقی قسمت ها نیاز به تغییر ندارند.

 IEnumerable<string> Subjects = from student in Objstudent
from st2 in student.Subjects
select st2;

در این روش متد SelectMany وجود ندارد و پیاده سازی آن با استفاده از دو select متوالی انجام خواهد گرفت که شباهت زیادی به Select های تودرتو در Sql دارد.

خروجی آن در تمامی موارد به صورت زیر خواهد بود.

خروجی مثال اول متد SelectMany
خروجی مثال اول متد SelectMany

به مثال دیگری از کاربرد این متد توجه کنید:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Linqtutorials
{
    class MainClass
    {
        static void Main(string[] args)
        {
            string[] strigArray =
             {
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
                "0123456789"
            };
            var result = strigArray.SelectMany(s =>s);
            foreach (char item in result)
            {
                Console.Write(item+" ");
            }
            Console.ReadKey();
        }
    }
}

در این مثال ساده دو عبارت رشته ای در یک آرایه از جنس String قرار دارند، حال قصد داریم اطلاعات موجود در این آرایه که هر کدام حاصل قرار گیری تعدادی کاراکتر هستد را استخراج کنیم. برای بررسی صحت این موضوع موس را بر روی result قرار دهید تا نوع آن نمایش داده شود. کد را اجرا کنید و خروجی را مشاهده کنید، خواهید دید که خروجی به صورت char نمایش داده می شود. برای درک بهتر موضوع می توانید فرض کنید که ابتدا یک Select به آرایه و یک Select به اعضای آن اعمال می کنیم تا به صورت char قابل دسترسی باشند.

برای درک بهتر موضوع تغییرات زیر را در کد اعمال کنید تا تفاوت Select و SelectMany را بهتر متوجه شوید؛ سپس خروجی را با دقت مشاهد کنید:

var result = strigArray.Select(s =>s);
            foreach (string item in result)
            {
                Console.Write(item+" ");
            }

می بینید که خروجی به صورت دو عنصر String است یعنی دقیقا عناصر موجود در آرایه ی strigArray در خروجی مشاهده می شوند. در واقع در این جا فقط یک select اجرا شده است. در ضمن به نوع متغیر result بار دیگر توجه و با قسمت قبل مقایسه کنید.

خروجی در حالت اول (قبل از تغییر SelectMany)
خروجی در حالت اول (قبل از تغییر SelectMany)
خروجی در حالت دوم (بعد از تغییر SelectMany به Select)
خروجی در حالت دوم (بعد از تغییر SelectMany به Select)

به عنوان تمرین این مثال را با استفاده از روشquery بازنویسی (مانند مثال اول) و خروجی را مشاهده کنید.

جواب تمرین

using System;
using System.Linq;

namespace Linqtutorials
{
    class MainClass
    {
        static void Main(string[] args)
        {
            string[] strigArray =
             {
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
                "0123456789"
            };
            var result = from str in strigArray
                         from ch in str
                         select ch;
            foreach (char item in result)
            {
                Console.Write(item + " ");
            }
            Console.ReadKey();
        }
    }
}

می بینید که تنها با یک تغییر کوچک می توان روش گرفتن اطلاعات را تغییر داد که البته نوع متغیر result مانند قبل بوده و هیچ گونه تغییری نخواهد داشت.

این بخش از آموزش به پایان رسید، در بخش بعدی آموزش با Filtering Operator آشنا خواهیم شد و مثال هایی در رابطه با آن حل می کنیم.

موفق باشید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش LINQ توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (2 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

sobhan
20 آذر 1400
سلام واقعا مرسی بابت این آموزش ها عالی و کاربردی هستند

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

ابوالفضل
17 دی 1399
عالی بودید.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.