92. Select extension method

בהמשך לטיפ של אתמול,

הפונקציה הכי בסיסית שיושבת בSystem.Linq במחלקה הסטטית Enumerable נקראת Select.

פונקציה זאת מקבלת IEnumerableוdelegate מסוג Func ומחזירה IEnumerable שנוצר ע”י הפעלת הdelegate על כל האיברים של הIEnumerable.

לדוגמה:

1
2
3
4
IEnumerable<Person> family = GetFamilyMembers("Banani");
IEnumerable<string> names =
family.Select(person => person.FirstName);

הדוגמה יוצרת לנו IEnumerable<string>שמכיל את השמות הפרטיים של כל האנשים במשפחה.

נוכל גם לעשות דברים יותר מתוחכמים:

1
2
3
4
5
IEnumerable<string> names =
family.Select(person =>
string.Format("{0} {1}",
person.FirstName,
person.LastName));

מחזיר לנו את כל השמות המלאים של כל האנשים במשפחה.

המימוש הוא משהו בסגנון:

1
2
3
4
5
6
7
8
9
public static IEnumerable<TResult> Select<T, TResult>
(this IEnumerable<T> enumerable,
Func<T, TResult> selector)
{
foreach (T current in enumerable)
{
yield return selector(current);
}
}

שימו לב שהמימוש הוא באמצעות yieldreturn ולכן הוא lazy – הSelect מחושב on the fly כאשר כל פעם שמתבצע MoveNext, מתבצעת איטרציה של הפונקציה. (ראו גם טיפים 54 ו55)


כדי שלא תגידו שלא לומדים כלום מהטיפ היומי, הנה משהו שפחות מוכר:

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

נראה שלא פשוט לעשות זאת, אבל קיים overload של Select שמאפשרת להתחשב באינדקס:

1
2
3
4
5
6
7
8
9
10
11
12
public static IEnumerable<TResult> Select<T, TResult>
(this IEnumerable<T> enumerable,
Func<T, int, TResult> selector)
{
int index = 0;
foreach (T current in enumerable)
{
yield return selector(current, index);
index++;
}
}

לדוגמה:

1
2
3
4
5
6
IEnumerable<string> names =
family.Select((person, index) =>
string.Format("{0}. {1} {2}",
index,
person.FirstName,
person.LastName));

יום שפה מובנית שאילתא טוב

שתף