119. OrderBy ThenBy extension methods

לפעמים אנחנו מעוניינים למיין אוסף של איברים באיזושהי צורה.

לדוגמה, למיין אנשים לפי הגיל שלהם, או למיין פירות לפי הכמות שלהם במלאי..

למרבה המזל, קיים Extension Method של Linq בשם OrderBy המאפשר לנו למיין אוסף.

לדוגמה:

1
2
IOrderedEnumerable<Person> orderedByAge =
people.OrderBy(person => person.Age);

אנחנו מעבירים לו delegate המציין לפי מה לבצע את המיון. בדוגמה זו, אנחנו ממיינים את האנשים לפי הגילאים שלהם.

דוגמה נוספת: נניח שיש לנו רשימה של שמות של פירות. אנחנו יכולים למיין אותם אלפא-ביתית (לפי סדר הופעתם במילון):

1
2
3
4
5
IEnumerable<string> fruits =
new[] {"Banana", "Orange", "Strawberry", "Apple", "Mango", "Grapes", "Lemon"};
IOrderedEnumerable<string> orderedFruits = fruits.OrderBy(fruit => fruit);
// "Apple","Banana","Grapes","Lemon","Mango","Orange","Strawberry"

אבל אנחנו יכולים גם למיין אותם לפי אורך השמות:

1
2
IOrderedEnumerable<string> orderedByLength = fruits.OrderBy(fruit => fruit.Length);
// "Apple","Mango","Lemon","Banana", "Orange","Grapes","Strawberry"

אתם יכולים לתהות מה זה IOrderedEnumerable? ובכן, זהו ממשק שמאפשר לנו לבצע מיון משני.

מה זאת אומרת? למה זה טוב?

נסביר קודם איך עובד OrderBy:

מה שקורה זה שברגע שאנחנו קוראים לGetEnumerator (למשל בforeach), מתבצעת ריצה על כל האיברים של הIEnumerable, ומתבצע quick sort שלהם.

זה קצת בעייתי, אבל כדי למיין אוסף, צריך לדעת את כל האיברים שלו…

עכשיו, אם נשרשר כמה OrderByים אחד אחרי השני מה שיקרה זה שכל שרשור של OrderBy יגרור מיון מחדש של כל איברי הרשימה. כלומר בדוגמה הזאת:

1
2
IOrderedEnumerable<string> orderedFruits =
fruits.OrderBy(fruit => fruit).OrderBy(fruit => fruit.Length);

מתבצעים שני מיונים. כלומר שני Quick Sortים. זהו תהליך יקר יחסית.

במקום זאת, הExtension Method ששמו ThenBy מאפשר לנו להתלבש על מיון שעדיין לא התבצע, ולומר לו שבמיון שהוא הולך לבצע, שימיין משנית לפי איזשהו שדה אחר:

1
2
IOrderedEnumerable<string> orderedFruits =
fruits.OrderBy(fruit => fruit.Length).ThenBy(fruit => fruit);

כאן מה שקורה זה שמתבצע Quick Sort יחיד כדי לבצע את המיון + המיון השני…

שימו לב שכל זה אפשרי בגלל שOrderBy זה lazy – עד שלא נקרא לGetEnumerator, המיון לא יתבצע ולכן נוכל להוסיף עוד קריטריונים למיון…

(ראו גם טיפים מספר 51 – 55)

הערה: לוגית, גם לא נכון למיין פעמיים, במידה ואלגוריתם המיון אינו יציב.

המשך יום ממוין טוב

שתף