267. IStructuralComparable interface

בדומה לפעמים הקודמות, קיימים לנו בFramework הממשקים IComparable וIComparer המאפשרים לנו להשוואות Instanceים של אובייקטים.

(ראו גם טיפים מספר 117-125)

גם כאן, לפעמים היינו רוצים להשוואות מבנים מורכבים מסוימים בעזרת איזשהו Comparer:

לדוגמה, נניח שיש לנו מערך של מערכים, יכול להיות שאנחנו מעוניינים להשוות את המערכים הפנימיים לפי המקסימום שלהם.

דוגמה נוספת, נניח שיש לנו רשימה של אנשים. יכול להיות שנניח אנחנו מעוניינים להשוות אנשים לפי הגילאים שלהם, אבל היינו רוצים להשוות אותם לפי טווחי גילאים, למשל ילדים/נוער/מבוגרים.

גם כאן, נוסף לנו בFramework 4.0 ממשק בשםIStructuralComparable המאפשר לנו להשוות אובייקט מורכב לפי האובייקטים הפנימיים שלו בעזרתComparer.

הממשק נראה כך:

1
2
3
4
public interface IStructuralComparable
{
int CompareTo(object other, IComparer comparer);
}

גם פה, מערכים וTupleים מממשים אותו Explicitly (ראו גם טיפ מספר 82):

לדוגמה, נניח שיש לנו מערך של מערכים ואנחנו מעוניינים להשוות את המערכים הפנימיים לפי המקסימום שלהם:

נכתוב Comparer רגיל:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ArrayMaxComparer : Comparer<int[]>
{
public override int Compare(int[] x, int[] y)
{
int firstMax = x.Max();
int secondMax = y.Max();
if (firstMax > secondMax)
{
return 1;
}
else if (firstMax < secondMax)
{
return -1;
}
return 0;
}
}

ואז נוכל להשתמש בו בשביל להשוות שני מערכים באותו גודל של מערכים:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int[][] numbers =
new[]
{
new[] {1},
new[] {1, 2, 3},
new[] {5, 8}
};
int[][] otherNumbers =
new[]
{
new[] {1, 3, 3, 1},
new[] {1, 4, 6, 4, 1},
new[] {1, 5, 10, 10, 5, 1}
};
IStructuralComparable numbersStructuralComparable = numbers;
int result =
numbersStructuralComparable.CompareTo(otherNumbers, new ArrayMaxComparer()); // -1

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

מתבצעת השוואה לקסיקוגרפית על המערכים לפי הComparer שמועבר. מה זאת אומרת?

תחשבו על זה כמו השוואה במילון – רצים על כל האיברים של המערך הראשון והשני במקביל. משווים כל שני איברים עד שמוצאים שני איברים שהם לא שווים מבחינת הComparer. מחזירים את התוצאה של הCompareTo של שני האיברים הנ"ל (האיבר המתאים מהמערך הראשון והאיבר המתאים מהמערך השני)

גם עבור Tuple הדבר מומש בצורה טובה – משווים רכיב רכיב עד שמוצאים רכיב עבורו לא מתקיים שהCompareTo בין הרכיבים של שני הInstanceים הוא 0. ברגע שמוצאים כזה, מחזירים את התוצאה.

זה מתאים למקרים בהם אנחנו מעוניינים להשוות את הטיפוסים שלנו לפי שדות, כאשר יש עדיפות לשדות, למשל קודם לפי שם פרטי, לאחר מכן לפי שם משפחה, אחר כך לפי גיל וכו’…

המשך יום מובנה בר השוואה טוב.

שתף