102. Aggregate extension method

אחת המתודות הפחות מוכרות מSystem.Linq היא Aggregate.

נניח שאנחנו רוצים לחשב סכום גילאים של כל האנשים באיזשהו אוסף.

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

1
2
3
4
5
6
int ageSum = 0;
foreach (Person person in family)
{
ageSum = ageSum + person.Age;
}

אם ננתח את מה שקורה כאן:

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

מסתבר שפעולה כזאת היא מאוד נפוצה, ואחת הפעולות הבסיסיות ב תכנות פונקציונאלי נקראת Reduce והיא מכלילה את מה שראינו עכשיו.

איך זה עובד? במקום לכתוב את מה שכתבנו עכשיו, נוכל לכתוב:

1
2
3
int ageSum =
family.Aggregate(0,
(current, person) => current + person.Age);

הפרמטר הראשון מציין את הערך ההתחלתי של "המשתנה", והפרמטר השני הוא delegate המציין במה להחליף את המשתנה בכל איטרציה.

בפועל מתבצעת הלולאה, ובסופו של דבר ageSum מקבל את הערך הסופי של המשתנה הזמני הנ"ל.

דוגמאות נחמדות הן כנ"ל:

נניח שיש לנו סל קניות, ובו כל איבר מציין סוג מוצר וכמות מאותו סוג:

1
2
3
4
5
6
public class ShoppingCartItem
{
// ...
public double Price { get; }
public int Amount { get; }
}

נניח שאנחנו רוצים לחשב את הסכום הסופי שיש לשלם על סל קניות זה.

נוכל לכתוב זאת כך:

1
2
3
4
5
double totalCost =
shoppingCart.Aggregate
(0.0,
(price, currentItem) =>
price + currentItem.Amount * currentItem.Price);

אם נניח שנרצה יותר מזה – למשל, בסוף התהליך לעגל את המחיר למספר השלם הקרוב ביותר למחיר זה, נוכל לעשות זאת באמצעות overload אחר של Aggregate:

1
2
3
4
5
6
double totalCost =
shoppingCart.Aggregate
(0.0,
(price, currentItem) =>
price + currentItem.Amount * currentItem.Price,
price => Math.Round(price));

הoverload הנ"ל מקבל גם delegate לביצוע בעת סיום הלולאה.

הערה:

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

למשל, אפשר לחשב מינימום של כמות מוצרים שנקנתה:

1
2
3
4
5
int leastAmount =
shoppingCart.Aggregate
(0,
(amount, currentItem) =>
Math.Min(amount, currentItem.Amount));

ועוד ועוד, אין פה גבול ליצירתיות.

עוד הערה:

קיימות הExtension Methods בשמות Sum, Min, Max וכו’ המאפשרות לחשב סכום, מינימום ומקסימום מבלי להמציא את הגלגל.

הן, כמובן, עובדות בצורה דומה למה שעשינו כאן.

שתף