عملگرهای اتصال (Join Operators)
• Join
• GroupJoin
• Zip
عملگر Join
این عملگر همانند inner join در SQL، دو مجموعه را بر اساس کلیدهای مرتبط که از طریق پارامترها به آن ارسال میشوند، با یکدیگر ترکیب میکند.
در عملیات Join، یک توالی ورودی که به آن توالی خارجی (Outer Sequence) گفته میشود با یک توالی دیگر که به آن توالی داخلی (Inner Sequence) میگوییم، بر اساس کلیدهای مشخص شده، ترکیب شده و یک توالی خروجی تولید میشود.
بررسی پارامترهای عملگر Join:
• <Inner IEnumerable<TInner: نشان دهنده توالی داخلی میباشد.
• Func<Touter,Tkey> outerKeySelector : عنصر کلید، در توالی خارجی
• Func<Tinner,Tkey> innerKeySelector : عنصر کلید، در توالی داخلی
• Func<Touter,Tinner,Tresult> resultSelector : یک عبارت Lambda است که ظاهر عناصر خروجی را مشخص میکند.
نکته : بطور کلی T در پارامترهای بالا معرف Generic Type Parameter میباشد؛ T==>Type (هر نوع دادهای که ما مشخص کنیم).
نکته : عملگر Join یک امضاء دیگر نیز دارد که اجازه مشخص کردن IEqualityComparer را میدهد.
کد زیر استفاده از عملگر Join را نشان میدهد. توجه داشته باشید که اعلان صریح نوع دادهها در عبارات Lambda نوشته شده، فقط برای روشنتر شدن فرآیند عملیات میباشد.
تعریف دو آرایه از کلاسهای Recipe و Review:
خروجی مثال بالا:
سادهتر شدهی کد بالا:
همانطور که مشاهده میکنید در خروجی مثال بالا، عبارت Sachertorte مشاهده نمیشود. علت آن است که عملیات انجام شده، عملیات Left Join میباشد. بدین معنا که عناصری که در توالی خارجی هیچ عنصر متناظری در توالی داخلی ندارند، در توالی خروجی ظاهر نخواهند شد.
پیاده سازی توسط عبارتهای جستجو
کلمه کلیدی Join، در زمان استفاده از روش عبارتهای پرس و جو، مورد استفاده قرار گرفت. دستور Join در قسمت چهارم از این سری آموزشی بطور کامل بررسی شده است. کد زیر نحوه اجرای دستور Join را به روش عبارتهای پرس و جو، نشان میدهد.
نکته : بررسیها نشان داده است که استفاده از دستور Join، به روش عبارتهای پرس و جو نسبت به عملگرهای پرس و جو، خوانایی بیشتری دارد.
عملگر GroupJoin
نحوه عملکرد عملگر GroupJoin، شبیه عملگر Join میباشد؛ با این تفاوت که خروجی حاصل از دستور GroupJoin، یک ساختار سلسله مراتبی میباشد. توالی خروجی، مجموعهای از گروهها میباشد که هر گروه، تشکیل شدهاست از عناصر توالی درونی.
بررسی پارامترهای عملگر GroupJoin
• <Inner IEnumerable<TInner : نشان دهنده توالی داخلی
• Func<Touter,Tkey> outerKeySelector : عنصر کلید، در توالی خارجی
• Func<Tinner,Tkey> innerKeySelector : عنصر کلید، در توالی داخلی
• Func<Touter,Ienumerable<Tinner>,Tresult> resultSelector : قالب بندی گروههای تولید شده خروجی را مشخص میکند
کد زیر استفاده از عملگر GroupJoin را نشان میدهد :
خروجی مثال فوق:
همانطور که مشاهده میکنید گروه "Sachertorte" در خروجی اضافه شده است؛ در صورتی که هیچ عضوی ندارد.
پیاده سازی توسط عبارتهای جستجو
خروجی مثال فوق:
عملگر Zip
عملگر Zip، رفتاری متفاوت نسبت به عملگر GroupJoin و Join دارد و هیچ آیتمی را به عنوان کلید، از دو توالی دریافت نمیکند. عملگر Zip همه عناصر دو توالی را یک به یک، به ترتیب کنار هم قرار میدهد. مثل زیپ در دنیای واقعی که لبههای دو طرف زیپ را به هم میرساند.
خروجی مثال بالا :
نکته: اگر تعداد اعضای مجموعهها برابر نباشد، اعضای اضافی نادیده گرفته میشوند.
پیاده سازی توسط عبارتهای جستجو
معادل عملگر Zip، کلمه کلیدی در عبارتهای جستجو وجود ندارد. ترکیب دو روش میتواند خروجی دلخواه را تولید کند.
• Join
• GroupJoin
• Zip
عملگر Join
این عملگر همانند inner join در SQL، دو مجموعه را بر اساس کلیدهای مرتبط که از طریق پارامترها به آن ارسال میشوند، با یکدیگر ترکیب میکند.
در عملیات Join، یک توالی ورودی که به آن توالی خارجی (Outer Sequence) گفته میشود با یک توالی دیگر که به آن توالی داخلی (Inner Sequence) میگوییم، بر اساس کلیدهای مشخص شده، ترکیب شده و یک توالی خروجی تولید میشود.
بررسی پارامترهای عملگر Join:
public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult> (this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter,TKey> outerKeySelector, Func<TInner,TKey> innerKeySelector, Func<TOuter,TInner,TResult> resultSelector)
• Func<Touter,Tkey> outerKeySelector : عنصر کلید، در توالی خارجی
• Func<Tinner,Tkey> innerKeySelector : عنصر کلید، در توالی داخلی
• Func<Touter,Tinner,Tresult> resultSelector : یک عبارت Lambda است که ظاهر عناصر خروجی را مشخص میکند.
نکته : بطور کلی T در پارامترهای بالا معرف Generic Type Parameter میباشد؛ T==>Type (هر نوع دادهای که ما مشخص کنیم).
نکته : عملگر Join یک امضاء دیگر نیز دارد که اجازه مشخص کردن IEqualityComparer را میدهد.
کد زیر استفاده از عملگر Join را نشان میدهد. توجه داشته باشید که اعلان صریح نوع دادهها در عبارات Lambda نوشته شده، فقط برای روشنتر شدن فرآیند عملیات میباشد.
تعریف دو آرایه از کلاسهای Recipe و Review:
Recipe[] recipes = { new Recipe {Id = 1, Name = "Mashed Potato"}, new Recipe {Id = 2, Name = "Crispy Duck"}, new Recipe {Id = 3, Name = "Sachertorte"} }; // inner sequence Review[] reviews = { new Review {RecipeId = 1, ReviewText = "Tasty!"}, new Review {RecipeId = 1, ReviewText = "Not nice :("}, new Review {RecipeId = 1, ReviewText = "Pretty good"}, new Review {RecipeId = 2, ReviewText = "Too hard"}, new Review {RecipeId = 2, ReviewText = "Loved it"} }; var query = recipes // recipes توالی خارجی .Join(reviews, // reviewsتوالی داخلی (Recipe outerKey) => outerKey.Id, // کلید انخاب شده از توالی خارجی (Review innerKey) => innerKey.RecipeId, // کلید انتخاب شده از توالی داخلی // نحوه قالب بندی خروجی (recipe, review) => recipe.Name + " - " + review.ReviewText); foreach (string item in query) { Console.WriteLine(item); }
Mashed Potato - Tasty! Mashed Potato - Not nice :( Mashed Potato - Pretty good Crispy Duck - Too hard Crispy Duck - Loved it
var query = recipes.Join (reviews, outerKey => outerKey.Id, innerKey => innerKey.RecipeId, (recipe, review) => recipe.Name + " - " + review.ReviewText);
پیاده سازی توسط عبارتهای جستجو
کلمه کلیدی Join، در زمان استفاده از روش عبارتهای پرس و جو، مورد استفاده قرار گرفت. دستور Join در قسمت چهارم از این سری آموزشی بطور کامل بررسی شده است. کد زیر نحوه اجرای دستور Join را به روش عبارتهای پرس و جو، نشان میدهد.
var query = from recipe in recipes join review in reviews on recipe.Id equals review.RecipeId select new //انواع بی نام { RecipeName = recipe.Name, RecipeReview = review.ReviewText }; foreach (var item in query) { Console.WriteLine(item.RecipeName + " - " + item.RecipeReview); }
عملگر GroupJoin
نحوه عملکرد عملگر GroupJoin، شبیه عملگر Join میباشد؛ با این تفاوت که خروجی حاصل از دستور GroupJoin، یک ساختار سلسله مراتبی میباشد. توالی خروجی، مجموعهای از گروهها میباشد که هر گروه، تشکیل شدهاست از عناصر توالی درونی.
بررسی پارامترهای عملگر GroupJoin
• <Inner IEnumerable<TInner : نشان دهنده توالی داخلی
• Func<Touter,Tkey> outerKeySelector : عنصر کلید، در توالی خارجی
• Func<Tinner,Tkey> innerKeySelector : عنصر کلید، در توالی داخلی
• Func<Touter,Ienumerable<Tinner>,Tresult> resultSelector : قالب بندی گروههای تولید شده خروجی را مشخص میکند
کد زیر استفاده از عملگر GroupJoin را نشان میدهد :
// outer sequence Recipe[] recipes = { new Recipe {Id = 1, Name = "Mashed Potato"}, new Recipe {Id = 2, Name = "Crispy Duck"}, new Recipe {Id = 3, Name = "Sachertorte"} }; // inner sequence Review[] reviews = { new Review {RecipeId = 1, ReviewText = "Tasty!"}, new Review {RecipeId = 1, ReviewText = "Not nice :("}, new Review {RecipeId = 1, ReviewText = "Pretty good"}, new Review {RecipeId = 2, ReviewText = "Too hard"}, new Review {RecipeId = 2, ReviewText = "Loved it"} }; var query = recipes .GroupJoin( reviews, (Recipe outerKey) => outerKey.Id,//outer key (Review innerKey) => innerKey.RecipeId,//inner key (Recipe recipe, IEnumerable<Review> rev )=>تعریف ساختار گروهها new { RecipeName = recipe.Name, Reviews = rev } ); foreach (var item in query) { Console.WriteLine($"Reviews for {item.RecipeName}"); foreach (var review in item.Reviews) { Console.WriteLine($" - {review.ReviewText}"); } }
Reviews for Mashed Potato - Tasty! - Not nice :( - Pretty good Reviews for Crispy Duck - Too hard - Loved it Reviews for Sachertorte
پیاده سازی توسط عبارتهای جستجو
var query = from recipe in recipes join review in reviews on recipe.Id equals review.RecipeId into reviewGroup select new //انواع بی نام { RecipeName = recipe.Name, Reviews = reviewGroup//کلیه بازخوردها مرتبط با یک دستور غذایی };
Reviews for Mashed Potato - Tasty! - Not nice :( - Pretty good Reviews for Crispy Duck - Too hard - Loved it Reviews for Sachertorte
عملگر Zip
عملگر Zip، رفتاری متفاوت نسبت به عملگر GroupJoin و Join دارد و هیچ آیتمی را به عنوان کلید، از دو توالی دریافت نمیکند. عملگر Zip همه عناصر دو توالی را یک به یک، به ترتیب کنار هم قرار میدهد. مثل زیپ در دنیای واقعی که لبههای دو طرف زیپ را به هم میرساند.
public class Ingredient { public string Name { get; set; } public int Calories { get; set; } } string[] names = { "Flour", "Butter", "Sugar" }; int[] calories = { 100, 400, 500 }; IEnumerable<Ingredient> ingredients = names.Zip(calories, (name, calorie) => new Ingredient { Name = name, Calories = calorie }); foreach (var item in ingredients) { Console.WriteLine($"{item.Name} has {item.Calories} calories"); }
Flour has 100 calories Butter has 400 calories Sugar has 500 calories
پیاده سازی توسط عبارتهای جستجو
معادل عملگر Zip، کلمه کلیدی در عبارتهای جستجو وجود ندارد. ترکیب دو روش میتواند خروجی دلخواه را تولید کند.