با سلام خدمت کاربران عزیز در این جلسه قصد داریم چند اپراتور باقی مانده در مبحث LINQ را بررسی کنیم تا پیش نیاز لازم را برای شروع مبحث LINQ to SQL داشته باشیم و از جلسه ی بعدی به توضیح و بررسی آن بپردازیم.
کاربرد این متد زمانی است که می خواهیم کل عناصر یک مجموعه بر اساس الگوی خاصی رفتار کنند، این رفتار با شروع از عنصر اول و دوم و اعمال نتیجه به عنصر سوم و الی آخر انجام می شود. احتمالا توضیح آن کمی گیج کننده بود اجازه دهید با بررسی یک مثال کاربرد آن را شرح دهیم.
مثال:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] Num = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Console.WriteLine("Find the Product of the elements:"); double Average = Num.Aggregate((a, b) => a * b); Console.WriteLine("The Product is {0}", Average); string[] charlist = { "a", "b", "c", "d" }; var concta = charlist.Aggregate((a, b) => a + ',' + b); Console.WriteLine("Concatenated String: {0}", concta); Console.ReadLine(); } } }
در ابتدای برنامه یک آرایه int
در اختیار داریم که اعضای آن اعداد 1 تا 9 هستند. هدف ما گرفتن فاکتوریل از اعضای آرایه است.
فرمول فاکتوریل به این صورت است که عدد اول و دوم در هم ضرب می شوند و حاصل آن با عدد سوم ضرب و به همین صورت تا پایان ادامه پیدا می کند.
این الگو به راحتی در متد Aggregate
قابل پیاده سازی است برای این منظور کد a, b) => a * b)
درون متد می نویسیم. منظور از a عدد اول و b عدد دوم است. در مرحله ی اول a=1
و b=2
است که حاصل ضرب آن ها عدد 2 خواهد بود حالا a=2
(حاصل مرحله ی اول) و b=3 است که حاصل ضرب آن ها 6 خواهد بود به همین ترتیب در مرحله ی بعد a=6
و b=4
می شود تا به پایان برسد.
در مرحله ی بعد یک آرایه ی string
تعریف شده است که ما قصد داریم اعضای آن همراه با ','
یا هر چیز دیگری از هم جدا کنیم برای تکرار این الگو برای تمامی اعضا کدa, b) => a + "," + b)
را در متد می نویسیم.
برای پیاده سازی کد به روش Query باید تغییرات زیر را انجام دهید:
double Average = (from x in Num select x).Aggregate((a, b) => a * b); string concta = (from x in charlist select x).Aggregate((a, b) => a + "," + b);
همان طور که در خروجی مشخص است مقدار 9! محاسبه شده است و اعضای آرایه ی string
با ','
جدا شده اند.
حالا تغییرات زیر را در کد بالا اعمال کنید و خروجی را مشاهده کنید:
double Average = Num.Aggregate((a,b)=>(a+1)+b); string concta = charlist.Aggregate((a, b) => a + "->\t" + b);
در مرحله ی اول a=1
و b=2
خواهد بود. همان طور که در الگو مشخص شده ابتدا باید یک واحد به a اضافه و سپس با b جمع شود که حاصل برابر 4 خواهد شد در مرحله ی بعد a=4
و b=3
می شود. دوباره باید به مقدار a یک واحد اضافه و سپس با b جمع شود تا حاصل برابر 8 شود این عملیات تا رسیدن به آخرین عضو آرایه به همین ترتیب ادامه خواهد داشت تا در آخر عدد 53 حاصل شود.
در مورد آرایه ی string
هدف ما ابتدا چاپ ->
و سپس ایجاد کارکتر کنترلی "t\"
است. برنامه را اجرا و خروجی را مشاده کنید.
از این متد برای گروه بندی آیتم ها در یک مجموعه یا لیست بر اساس یک کلید خاص و یک فیلد استفاده می شود. این متد از نظر کاربرد تا حد زیادی به GroupBy
در SQL شباهت دارد.
به مثال زیر توجه کنید:
using System; using System.Collections.Generic; using System.Linq; namespace Linqtutorials { class Program { static void Main(string[] args) { List<Student> objStudent = new List<Student>() { new Student() { Name = "Suresh Dasari", Gender = "Male",Location="Chennai" }, new Student() { Name = "Rohini Alavala", Gender = "Female", Location="Chennai" }, new Student() { Name = "Praveen Alavala", Gender = "Male",Location="Bangalore" }, new Student() { Name = "Sateesh Alavala", Gender = "Male", Location ="Vizag"}, new Student() { Name = "Madhav Sai", Gender = "Male", Location="Nagpur"} }; var student = objStudent.GroupBy(x => x.Location); foreach (var sitem in student) { Console.WriteLine(sitem.Key+" "+ sitem.Count()); Console.WriteLine(); foreach (var stud in sitem) { Console.WriteLine(stud.Name + "\t" + stud.Location); } Console.WriteLine(); } Console.ReadLine(); } } class Student { public string Name { get; set; } public string Gender { get; set; } public string Location { get; set; } } }
هدف ما در این مثال مرتب سازی اعضای یک مجموعه بر اساس فیلد Location
است. توجه داشته باشید که در این متد منظور از Key همان فیلدی است که اطلاعات بر اساس آن طبقه بندی می شود که در این مثال مقدار Key فیلد Location
است.
در foreach
اول هدف ما چاپ مقادیر فیلد Location
و تعداد آن است همان طور که مشاهده می کنید برای دستیابی به مقادیر فیلد از کلمه ی Key استفاده شده است.
در foreach
دومی که در داخل اولی قرار دارد، قصد داریم به فیلد های کلاس Student
دست پیدا کنیم به همین منظور بر روی شئ پیمایش کننده حلقه ی اول یک پیمایش دیگر انجام می دهیم اگر موس را بر روی stud
قرار دهید می بینید که شئ از کلاس Student
است. بنابراین به تمامی فیلد های آن دسترسی دارد و می توان با دستور مناسب آن را چاپ نمود.
روش Query:
var student = from x in objStudent.GroupBy(x => x.Location) select x;
یا
var student = from x in objStudent group x by x.Location;
احتمالا متوجه شدید که این متد شباهت بسیار زیادی به متد ToLookup
دارد حالا اجازه دهید همین مثال را با متد ToLookup
تغییر دهیم و آن را بررسی کنیم.
تغییرات زیر را بر روی مثال قبلی انجام دهید:
var student = objStudent.ToLookup(x => x.Location); foreach (var sitem in student) { Console.WriteLine(sitem.Key+" "+ sitem.Count()); Console.WriteLine(); foreach (var stud in student[sitem.Key]) { Console.WriteLine(stud.Name + "\t" + stud.Location); } Console.WriteLine(); }
فقط کافی است جای GroupBy
را با ToLookup
عوض کنید در ضمن در کد بالا در حلقه ی دوم می توانید به جای [student[sitem.Key
از sitem
(پیمایشگر حلقه ی اول) استفاده کنید.
اگر کد را اجرا کنید می بینید که خروجی دقیقا مانند قبل است فقط روش پیاده سازی آن متفاوت است.
یک متد مقایسه گر است که تست تساوی را بر روی دو دنباله از اطلاعات انجام می دهد. خروجی این متد در صورتی که تمامی عناصر یک مجموعه دو به دو یکسان باشند true و در غیر این صورت false است.
به مثال زیر توجه کنید:
using System; using System.Collections.Generic; using System.Linq; namespace Linqtutorials { class Program { static void Main(string[] args) { string[] arr1 = { "welcome", "to", "tutlane", "com" }; string[] arr2 = { "welcome", "TO", "TUTLANE", "com" }; string[] arr3 = { "welcome", "to", "tutlane" }; string[] arr4 = { "WELCOME", "TO", "TUTLANE" }; bool res1 = arr1.SequenceEqual(arr2); bool res2 = arr1.SequenceEqual(arr2, StringComparer.OrdinalIgnoreCase); bool res3 = arr1.SequenceEqual(arr3); bool res4 = arr3.SequenceEqual(arr4, StringComparer.OrdinalIgnoreCase); Console.WriteLine("Result1: {0}", res1); Console.WriteLine("Result2: {0}", res2); Console.WriteLine("Result3: {0}", res3); Console.WriteLine("Result4: {0}", res4); Console.ReadLine(); } } }
اعضای موجود در آرایه های arr1
و arr2
کاملا یکسان هستند اما در کوچک و بزرگ بودن حروف متفاوت اند. در دو آرایه ی arr3
و arr4
هم شرایط به همین صورت است. با استفاده از متد SequenceEqual
شرایط تساوی را بررسی کردیم. برنامه را اجرا و خروجی را مشاهده کنید می بینید که Result1
و Result3
هر دو false هستند.
Result1
حاصل تست تساوی بین دو آرایه ی arr1
و arr2
است. پس نتیجه می گیریم که متد SequenceEqual
به بزرگ یا کوچک بودن حروف حساس است برای این که این حساسیت را از بین ببریم باید از StringComparer.OrdinalIgnoreCase
در متد استفاده کنیم. می بینید که Result2 و Result4 هر دو true هستد چون در بررسی تساوی از StringComparer.OrdinalIgnoreCase
در متدSequenceEqual
استفاده کرده ایم.
توجه: این روش تست تساوی برای کلاس ها با Property های مختلف قابل پیاده سازی نیست. یکی از راه های بررسی تساوی میان دو شئ از یک کلاس پیاده سازی واسط IComparable
برای آن کلاس و نوشتن متد CompareTo
است.
همان طور که از نام این متد ساده پیداست کاربرد آن در وصل کردن دو مجموعه به یکدیگر است به طوری که اگر در دو مجموعه عنصری تکراری وجود داشته باشد آن عنصر حذف نخواهد شد و در مجموعه ی جدیدی که حاصل اتصال دو مجموعه قبلی است عنصر تکراری به دفعات تکرار در دو مجموعه قبلی تکرار خواهد شد.
این متد تا حدودی شبیه به Union
است با این تفاوت که متد Union عناصر تکراری را حذف می کرد و در مجموعه ی جدید عنصری که دارای تکرار بود فقط یک بار در نظر گرفته می شد. برای درک بیشتر به شکل زیر که مفهوم کلی متد Concat
را نشان می دهد توجه کنید:
مثال :
using System; using System.Collections.Generic; using System.Linq; namespace Linqtutorials { class Program { static void Main(string[] args) { string[] arr1 = { "a", "b", "c","b", "d" }; string[] arr2 = { "c", "d", "e", "f","a" }; IEnumerable<string> result = arr1.Concat(arr2); string res = result.Aggregate((a,b)=>a+","+b); foreach (var item in res) { Console.Write(item); } Console.ReadLine(); } } }
در این مثال دو آرایه ی arr1
و arr2
که هر دو دارای عناصر تکراری هستند و با استفاده از متد Concat
به هم متصل شده اند. مشاهده می کنید که هیچ حذفی صورت نگرفته و تمامی عناصر تکراری در خروجی چاپ شده اند.
روش Quey:
IEnumerable<string> result = (from x in arr1 select x).Concat(arr2);
از این متد برای تولید دنباله ای از اعداد در یک محدوده ی خاص استفاده می شود.
الگوی استفاده از آن به صورت زیر است:
IEnumerable<int> obj = Enumerable.Range(int start, int count);
این متد بر روی هیچ مجموعه یا شئ فراخوانی نمی شود و به صورت static استفاده می شود و در کلاس Enumerable
قرار دارد. هر دو پارامتر ورودی آن از نوع int
هستند که اولی مشخص می کند، تولید دنباله از چه عددی شروع شود و پارامتر دوم تعداد اعضای دنباله را مشخص می کند.
به مثال زیر توجه کنید:
using System; using System.Collections.Generic; using System.Linq; namespace Linqtutorials { class Program { static void Main(string[] args) { IEnumerable<int> obj = Enumerable.Range(100, 50); foreach (var item in obj) { Console.WriteLine(item); } Console.ReadLine(); } } }
در این مثال شروع شمارش از 100 و تعداد آن ها 10 در نظر گرفته شده بنابراین خروجی از 100 تا 109 خواهد بود که توسط foreach
قابل دستیابی است.
این متد یک عدد را به تعداد مرتبه ی مشخصی تکرار می کند که الگوی استفاده از آن به صورت زیر است:
IEnumerable<int> obj = Enumerable.Repeat(int element, int count);
این متد بر روی هیچ مجموعه یا شئ فراخوانی نمی شود و به صورت static استفاده می شود و در کلاس Enumerable
قرار دارد. هر دو پارامتر ورودی آن از نوع int
هستند که اولی مشخص می کند، چه عددی باید تکرار شود و پارامتر دوم تعداد تکرار را مشخص می کند.
به مثال زیر توجه کنید:
using System; using System.Collections.Generic; using System.Linq; namespace Linqtutorials { class Program { static void Main(string[] args) { IEnumerable<int> obj = Enumerable.Repeat(524, 3); foreach (var item in obj) { Console.WriteLine(item); } Console.ReadLine(); } } }
در این مثال عدد 524 که پارامتر اول متد Repeat
است 3 با تکرار می شود.
خب دوستان مقدمه ی آموزش LINQ در C# در این بخش به پایان می رسد. در طول دوره ی مقدماتی سعی شد متدهایی که کاربرد بیشتری دارند با مثال های بیشتری بررسی شوند. متدهایی مثل AsEnumerable
و Cast
و Range
و چند متد دیکر که کمتر در مورد آن ها بحث شد متدهایی هستند که به تنهایی هیچ کاربردی ندارند و استفاده از آن ها بی معنی است و زمانی کاربرد آن ها مفید است که در کنار دیگر متدها استفاده شود.
در قسمت های بعدی آموزش سعی می شود در مثال های پیچیده تر از این متدها استفاده کنیم تا کاربرد دقیق آن ها درک کنید. کلیه ی مثال های بررسی شده در طی این دوره شامل مبحث LINQ to Object بودند بنابراین از قسمت بعدی آموزش مبحث LINQ to SQL را شروع می کنیم.
موفق باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.