305. Scan extension method

הכרנו בעבר (טיפ מספר 102) את הפונקציה Aggregate, המאפשרת לנו לחשב את התוצאה של פעולה איטרטיבית.

פונקציה זו מקבילה לפעולה Reduce מתכנות פונקציונאלי:

בנוסף, הכרנו את הפונקציה Select (טיפ מספר 92) הממפה לנו אוסף של איברים לאוסף אחר של איברים ע”י הפעלת פונקציה מסוימת על כל אחד מהאיברים באוסף.

פונקציה זו מקבילה לפעולה Map מתכנות פונקציונאלי.

בנוסף, קיימת פעולה נוספת בתכנות פונקציונאלי המשלבת את שתי הפעולות, שנקראת Map-Reduce, היא מבצעת איטרציות כמו Map, אבל מחזירה אוסף של תוצאות של האיטרציות (בדומה לReduce).

לצערנו, אין פונקציה כזאת בSystem.Linq, אבל נוכל לממש אותה (למעשה, מימשו אותה בReactive Extensions בגרסאות המוקדמות, והיום זה נמצא בהרחבה אחרת שנקראת Interactive Extensions).

המימוש נראה כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static IEnumerable<TAccumulate> Scan<TSource, TAccumulate>
(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
TAccumulate accumulate = seed;
foreach (TSource current in source)
{
yield return accumulate;
accumulate = func(accumulate, current);
}
yield return accumulate;
}

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

1
2
3
4
5
6
7
8
9
IEnumerable<int> sums =
Enumerable.Range(1, 10).Scan(0, (result, current) => current + result);
foreach (int sum in sums)
{
Console.WriteLine(sum);
}
// 0,1,3,6,10,15,21,28,36,45,55

בברכת זה שאני לא נמצא, לא אומר שהטיפ היומי מת,

המשך יום טוב!

שתף