عبارت orderby
LINQ این امکان را فراهم کرده است که ترتیب نتایج پرس و جو را تغییر دهید. برای این کار از عبارت orderby استفاده میکنیم. در هنگام نوشتن این عبارت باید یک مقدار یا خاصیت را به عنوان کلید مرتب سازی مشخص کنیم. به عنوان مثال، فرض کنید آرایهای از اعداد را ایجاد کردهایم و قصد داریم روی این آرایه پرس و جویی را انجام دهیم و سپس نتیجه پرس و جو را از بزرگترین به کوچکترین عدد مرتب کنیم، میتوانیم از پرس و جویی به شکل زیر استفاده کنیم :
int[] numbers = { 5, 1, 6, 2, 8, 10, 4, 3, 9, 7 }; var sortedNumbers = from number in numbers orderby number select number;
مرتب سازی نتایج پرس و جوی بالا را با استفاده از عبارت orderby انجام دادهایم و کلید مرتب سازی را خود عدد انتخاب کردهایم. هنگامی که برای کلید مرتب سازی خود شیء را انتخاب میکنید رفتار پیشفرض آن شیء در نظر گرفته میشود. به عنوان مثال، عبارت بالا مقدار هر شیء پرس و جو شده را از لحاظ کوچکتر یا بزرگتر بودن با شیء پرس و جو شده دیگر مقایسه میکند.
مرتب سازی پیشفرض این عبارت از پایینترین به بالاترین مقدار است. با استفاده از کلمه کلیدی ascending میتوان صراحتاً تعیین کرد که نتیجه پرس و جو به صورت صعودی مرتب شود.
var sortedNumbers = from number in numbers orderby number ascending select number;
برای معکوس کردن نتیجه یعنی مرتب کردن نتایج به صورت نزولی از کلمه کلیدی descending استفاده میشود.
var sortedNumbers = from number in numbers orderby number descending select number;
در هنگام کار با نوعهای پیچیده مانند کلاسها میتوانید از خصوصیت آنها به عنوان کلید مرتب سازی استفاده کنید. به عنوان مثال، فرض کنید مجموعهای از اشیاء که همگی دارای نوع Person هستند در اختیار داریم. این نوع دارای خصوصیاتی به نامهای FirstName ، LastName ، Age است. با استفاده از پرس و جوی زیر کلکسیون را از جوانترین به مسنترین فرد مرتب میکنیم :
var sortedByAge = from person in people orderby person.Age select person;
اگر قصد دارید نتیجه عبارت بالا را از مسنترین به جوانترین تغییر دهید در جلوی کلید از کلمه کلیدی descending استفاده کنید. همچنین میتوان نتیجه را بر اساس حرف اول نام خانوادگی اشخاص مرتب کنیم.
var sortedByFirstName = from person in people orderby person.LastName select person;
اگر دو شخص با نام خانوادگی یکسان در مجموعه داشته باشیم مرتب سازی آنها به چه شکلی است؟ برای حل این مشکل میتوانید چند کلید را برای مرتب سازی تعیین کنید.
var sortedByFnThenLn = from person in people orderby person.LastName, person.FirstName select person;
کلیدها را با استفاده از کاما از یکدیگر جدا میکنیم.
پرس و جو بالا نتیجه را بر ااساس نام خانوادگی اشخاص مرتب میکند و اگر دو شخص نام خانوادگی یکسانی داشته باشند با استفاده از خاصیت نام، آنها را مرتب میکند. همچنین میتوانید کلیدهای بیشتری را نیز مشخص کنید مثلاً برای زمانی که دو شخص نام یکسانی داشته باشند. به این نکته توجه کنید که کلمات کلیدی ascending و descending فقط روی یک مقدار در عبارت orderby عمل میکنند. به عنوان مثال، کوئری زیر را در نظر بگیرید :
var orderByResults = from person in people orderby person.LastName, person.FirstName descending select person;
کلمه کلیدی descending فقط بر روی مقدار خاصیت پیش از خود (در مثال بالا FirstName ) تأثیر میگذارد. مقدار خاصیت LastName به طور پیشفرض به صورت صعودی مرتب میشود. برای جلوگیری از آشفتگی توصیه میشود به طور صریح کلمه کلیدی ascending را بنویسید :
var orderByResults = from person in people orderby person.LastName ascending, person.FirstName descending select person;
برای اینکه رفتار پیشفرض یک کلاس را هنگام مرتب سازی تعیین کنید باید رابط IComparable<T> را در کلاس پیاده سازی نمایید. در مثال زیر کلاس Person رابط IComparable<T> را پیاده سازی کرده است :
1: using System; 2: using System.Linq; 3: using System.Collections.Generic; 4: 5: namespace OrderByClause 6: { 7: class Person : IComparable<Person> 8: { 9: public string FirstName { get; set; } 10: public string LastName { get; set; } 11: public int Age { get; set; } 12: 13: public Person(string f, string l, int a) 14: { 15: FirstName = f; 16: LastName = l; 17: Age = a; 18: } 19: 20: public int CompareTo(Person other) 21: { 22: if (this.Age > other.Age) 23: return 1; 24: else if (this.Age < other.Age) 25: return -1; 26: else 27: return 0; 28: } 29: } 30: 31: class Program 32: { 33: static void Main(string[] args) 34: { 35: List<Person> people = new List<Person>() 36: { 37: new Person("Peter" , "Redfield", 32), 38: new Person("Marvin", "Monrow" , 17), 39: new Person("Aaron" , "Striver" , 25) 40: }; 41: 42: var defaultSort = from person in people 43: orderby person 44: select person; 45: 46: foreach (var person in defaultSort) 47: { 48: Console.WriteLine(String.Format("{0} {1} {2}", person.Age, person.FirstName, person.LastName)); 49: } 50: } 51: } 52: }
17 Marvin Monrow 25 Aaron Striver 32 Peter Redfield
خط 7 بیانگر پیاده سازی رابط IComparable<T> است. باید نوع اشیایی که با یکدیگر مقایسه میشوند را به جای T قرار دهیم در مثال این نوع برابر Person است. پیاده سازی این رابط مستلزم پیاده سازی یک متد با نام CompareTo() است. این متد یک شیء به عنوان پارامتر قبول میکند که باید با شیء جاری مقایسه شود سپس یک عدد صحیح به عنوان نتیجه بر میگرداند.
در مثال بالا این متد در خطوط 20 تا 28 پیاده سازی شده است. در داخل متد، مقدار خاصیت Age شیء جاری با خاصیت مشابه شیء دیگر (که در این مثال از نوع Person است) مقایسه شده است. اگر مقدار شیء جاری از مقدار دیگری بزرگتر باشد عددی بزرگتری از صفر، اگر مساوی باشد مقدار صفر و اگر کوچکتر از صفر باشد مقداری منفی به عنوان نتیجه برگشت داده میشود. با توحه به اینکه این کلاس رابطه IComparable<T> را پیاده سازی کرده است میتوانیم کوئری خود را سادهتر بنویسیم. چون در داخل متد CompareTo از خاصیت Age برای مقایسه استفاده کردهایم اگر در داخل کوئری کلید مرتب سازی نوشته نشود به طور پیشفرض خاصیت Age به عنوان کلید مرتب سازی در نظر گرفته میشود.
متدهای OrderBy() و OrderByDescending() موجود در فضای نامی System.Linq معادل عبارت orderby هستند. متد OrderBy() نتیجه پرس و جو را بر اساس یک کلید به صورت صعودی و OrderByDescending نتیجه را به صورت نزولی مرتب میکنند. برای مشخص کردن کلید مرتب سازی از یک عبارت لامبدا استفاده میکنیم.
using System; using System.Linq; using System.Collections.Generic; namespace OrderByClause { class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public Person(string f, string l, int a) { FirstName = f; LastName = l; Age = a; } } class Program { private static List<Person> GetPersonList() { List<Person> people = new List<Person>() { new Person("Peter" , "Redfield", 32), new Person("Marvin", "Monrow" , 17), new Person("Aaron" , "Striver" , 25) }; return people; } static void Main(string[] args) { List<Person> people = GetPersonList(); Console.WriteLine("Persons OrderBy FirstName : "); var orderByQuery3 = people.OrderBy(person => person.FirstName); foreach (var person in orderByQuery3) { Console.WriteLine(String.Format("{0}", person.FirstName)); } Console.WriteLine("\nPersons OrderByDescending Age : "); var orderByQuery4 = people.OrderByDescending(person => person.Age); foreach (var person in orderByQuery4) { Console.WriteLine(String.Format("{0}", person.Age)); } } } }
متدهای ThenBy() و ThenByDescending()
اگر چندین کلید مرتب سازی باشید باید از متدهای ThenBy() و ThenByDescending() استفاده کنید. به عنوان مثال کوئری Linq زیر :
var orderByQuery5 = from p in people orderby p.LastName, p.FirstName select p;
معادل کوئری به شکل زیر است :
people.OrderBy(p => p.LastName).ThenBy(p => p.FirstName);
اگر فصد داشته باشید با استفاده از کلید دوم نتیجه را به صورت نزولی مرتب کنید باید از متد ()ThenByDescending استفاده کنید :
var orderByQuery6 = people.OrderBy(p=>p.LastName).ThenByDescending(p=>FirstName); var orderByQuery7 = people.OrderByDescending(p=>p.LastName) .ThenByDescending(p=>p.FirstName);
به این نکته توجه کنید که متدهای ThenBy() و ThenByDescending() عضوی از رابط IOrderedEnumerable<T> هستند. متد OrderBy کلکسیونی را بر میگرداند که این رابط را پیاده سازی میکند. پس قبل از فراخوانی متدهای ThenBy() و ThenByDescending() باید متد OrderBy() یا OrderByDescending() را فراخوانی کنید .
استفاده از رابط IComparer<T>
شکل دیگری از 4 متد مرتب سازی پیشین نیز وجود دارد که شی ای از نوع IComparer<T> را به عنوان آرگومان قبول میکنند. یک کلاس را ایجاد و رابط IComparer<TKey> را در آن پیاده سازی میکنیم. با این کار کلاس ایجاد شده مقایسه پذیر خواهد بود.
1: using System; 2: using System.Linq; 3: using System.Collections.Generic; 4: 5: namespace OrederByClause 6: { 7: class Person 8: { 9: public string FirstName { get; set; } 10: public string LastName { get; set; } 11: public int Age { get; set; } 12: 13: public Person(string f, string l, int a) 14: { 15: FirstName = f; 16: LastName = l; 17: Age = a; 18: } 19: } 20: 21: class FirstNameComparer : IComparer<Person> 22: { 23: public int Compare(Person x, Person y) 24: { 25: return x.FirstName.CompareTo(y.FirstName); 26: } 27: } 28: 29: class Program 30: { 31: static void Main(string[] args) 32: { 33: List<Person> people = new List<Person>() 34: { 35: new Person("Peter" , "Redfield", 32), 36: new Person("Marvin", "Monrow" , 17), 37: new Person("Aaron" , "Striver" , 25) 38: }; 39: 40: var orderByQuery8 = people.OrderBy(person => person, new FirstNameComparer()); 41: 42: foreach (var person in orderByQuery8) 43: { 44: Console.WriteLine(String.Format("{0}", person.FirstName)); 45: } 46: } 47: } 48: }
پیاده سازی این رابط مستلزم پیاده سازی متدی به نام Compare() است که عملکرد آن بسیار شبیه به متد ()CompareTo در رابط IComparable<T> است با این تفاوت که این متد، دو شیء را به عنوان آرگومان قبول میکند (خط 23). در مثال بالا با استفاده از متد ()CompareTo مربوط به کلاس String که یک عدد صحیح را برمی گرداند، خاصیت FirstName اشیاء را با یکدیگر مقایسه کردهایم (خط 25). در انتها میتوانیم یک نمونه از این کلاس را به عنوان آرگومان به متدهای OrderBy() ، OrderByDescending() ، ThenBy() ، ThenByDescending() ارسال کنیم (خط 40).
var orderByQuery8 = people.OrderBy(person => person, new FirstNameComparer());
آرگومان دوم کلید مرتب سازی را مشخص میکند. در متد بالا کلید person است و با کمک شئ FirstNameComparer متد به صورت خودکار نتایج را بوسیله خاصیت FirstName مرتب میکند. راه دیگر برای مرتب سازی نزولی، استفاده از متد Reverse() بر روی مجموعهای است که به صورت صودی مرتب سازی شده است.
var orderByQuery9 = (from person in people orderby person.FirstName select person).Reverse();
در مثال اول، کل پرس و جو را داخل پرانتز قرار داده و سپس متد Reverse() را فراخوانی کردهایم. مثال دوم شکل متدی پرس و جوی موجود در مثال اول است.
سلام جناب ابراهیمی همین الان لینک بالا را دیدم فقط گزینه های گوناگون مربوط به
متد ()Compare را داشت
سلام
شما به این موضوع دقت نکردید.string یا بهتره بگم کلاس string داخلش متد static به نام string.Compare داره ولی تو این مثال FirstName یک شی از کلاس string هست و متد compareTo از متد های غیر static کلاس string هست.
بنده هم الان امتحان کردم و متدی به نام CompareTo وجود دارد.
جمع بندی اینکه متد Compare یکی از متد های static کلاس string هست و فقط با استفاده از خود کلاس قابل دسترسی هست و CompareTo متد غیر static هست و برای دسترسی بهش باید یک شی تعریف کنید از کلاس مربوطه که اینجا هم دقیقا درست هست.
همچنین در لینکی که بالا تر آقای ابراهیمی قرار دادند اگر با دقت نگاه می کردید متدCompareTo هم وجود داشته.لینک زیر رو ببینید.من از همون لینکی که آقای ابراهیمی قرار داند این رو کلیک کردم.
https://msdn.microsoft.com/en-us/library/35f0x18w(v=vs.110).aspx
اینکه در سایت بالا نوشته شده String.CompareTo به این معنی نیست که با استفاده از خود کلاس string می توان به این متد دسترسی پیدا کرد.و صرفا برای اینکه نشان بدهد بخشی از این کلاس هست به این صورت نوشته شده.در همین لینک اگر پایین تر کدی که نوشته شده رو ببنید می بینید که static نیست پس برای دسترسی به اون حتما باید یک متغیر از string درست کنید
ما در کلاس string متد Compareداریم متدCompareTo نداریم
همین الان تست کردم
این لینک رو ببینید
https://msdn.microsoft.com/en-us/library/system.string_methods(v=vs.110).aspx
به این نکته توجه کنید : خاصیت FirstName از نوع string هست . این کلاس دارای متد CompareTo هست به همین دلیل می تونید رو خاصیت FirstName فراخوانیش کنید
متد CompareTo روی خاصیت FirstName فراخوانی شده است . این خاصیت از نوع string هست و چون متد CompareTo داخل کلاس string تعریف شده پس می تونید روی خاصیت FirstName فراخوانیش کنید . کلاس string دارای متد CompareTo هست.
متد Compare در اینترفیس IComparer قرار داره . این Interface رو داخل کلاس FirstNameComparer پیاده سازی کردیم و داخل متد Compare از متد CompareTo کلاس string استفاده کردیم .
تازه خود کلاس string هم دارای متدی به نام CompareTo نیست بلکه این کلاس داری متد به نام Compare هست
جناب ابراهیمی در سورس بالا اسم کلاس و اسم متد چیست
ایا اسم متد CompareToهست ایا اسم کلاس آن String هست
اسم متد در FirstNameCompareبه نام compare است شما در متن به آن اشاره دارین
باسلام
به نظرمیایدعبارت
در مثال بالا با استفاده از متد CompareTo کلاس String
باید باعبارت زیرتعویض شود
در مثال بالا با استفاده از متد Compare متعلق به کلاس FirstNameComparer
سلام ، اگر امکان داره بیشتر توضیح بدین ، واضح توضیح ندادین . ولی بررسیش کردم مشکلی نداشت
جناب ابراهیمی با سلام
در جایی سورس متد ()GetPersonList موجود نیست