לפעמים אנחנו נתקלים בצורך להחזיר יותר מאיבר אחד בפונקציה, או לחלופין בצורך לטפל בזוגות של איברים.
לפעמים אנחנו בכלל רוצים לעבוד עם שלשות/רביעיות וכלה בnיות (הכינוי המתמטי לאוסף סדור של n איברים, באנגלית נקרא Tuple)
עד לFramework 4.0 היינו יכולים לעשות מניפולציה כזאת:
1 2 3 4 5 6 7 8 9
| public static KeyValuePair<int, int> FindMaxAndMin(IEnumerable<int> numbers) { int max; int min; return new KeyValuePair<int, int>(min, max); }
|
(תעזבו האם נכון שתהיה פונקציה כזאת או לא)
כלומר לעשות שימוש מעוות בKeyValuePair כדי לשמור שני ערכים – אלא שאין לנו באמת מפתח וערך כאן.
(למי שלא מכיר את KeyValuePair, ראו גם טיפ 17)
דוגמא נוספת היא כזאת: נניח שאנחנו מעוניינים למצוא את כל השלשות של מספרים שלמים (a,b,c) בתחום מסוים כך שמתקיים השוויון
$ a^2+ b^2 = c^2 $
(לשלשות כאלה קוראים שלשות פיתגוריות)
כאן יהיה לנו יותר קשה להשתמש בKeyValuePair, כיוון שאנחנו מעוניינים לשמור שלשות.
בFramework 4.0 קיים פתרון יותר אלגנטי – קיימת מחלקה בשם Tuple המייצגת n-יה. למען הדיוק, קיימות מספר מחלקות גנריות כאלה, מאיבר יחיד עד שמינייה:
1 2 3 4 5 6 7 8
| public class Tuple<T1> public class Tuple<T1, T2> public class Tuple<T1, T2, T3> public class Tuple<T1, T2, T3, T4> public class Tuple<T1, T2, T3, T4, T5> public class Tuple<T1, T2, T3, T4, T5, T6> public class Tuple<T1, T2, T3, T4, T5, T6, T7> public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>
|
קיימות שתי דרכים להשתמש בזה:
הראשונה היא באופן דומה למה שראינו KeyValuePair:
1 2 3 4 5 6 7 8 9
| public static Tuple<int, int> FindMaxAndMin(IEnumerable<int> numbers) { int max; int min; return new Tuple<int, int>(min, max); }
|
וגישה תתבצע כך:
1 2 3
| Tuple<int, int> minAndMax = FindMaxAndMin(numbers); Console.WriteLine("Min is {0}", minAndMax.Item1); Console.WriteLine("Max is {0}", minAndMax.Item2);
|
קיימת דרך אחרת לאתחל, והיא באמצעות הoverloadים של הפונקציה הסטטית Tuple.Create:
1 2 3 4 5 6 7 8
| public static Tuple<int, int> FindMaxAndMin(IEnumerable<int> numbers) { int max; int min; return Tuple.Create<int, int>(min, max); }
|
למי שזוכר את טיפ מספר 28, אפשר לתת לקומפיילר לזהות לבד את הטיפוסים הגנריים:
1 2 3 4 5 6 7 8
| public static Tuple<int, int> FindMaxAndMin(IEnumerable<int> numbers) { int max; int min; return Tuple.Create(min, max); }
|
כך שיש פה יתרון בכתיבה 😃.
בדוגמה של שלשות פיתגוריות:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static IEnumerable<Tuple<int, int, int>> PythagoreanTriplets(int range) { for (int a = 0; a < range; a++) { for (int b = 0; b < range; b++) { for (int c = 0; c < range; c++) { if (a * a + b * b == c * c) { yield return Tuple.Create(a, b, c); } } } } }
|
ואם אנחנו רוצים יותר מ8 איברים? חשבו על זה ומציעים לנו את הפתרון הבא:
1 2 3 4 5 6 7
| var tenNumbers = new Tuple<int, int, int, int, int, int, int, Tuple<int, int,int>> (1, 2, 3, 4, 5, 6, 7, Tuple.Create(8, 9, 10)); Console.WriteLine(tenNumbers.Item6); Console.WriteLine(tenNumbers.Rest.Item2);
|
האמת שלא הכי אלגנטי, אבל עשוי להתאים.
שבוע טיזרים טוב