97. Select many query syntax

[נכתב ע”י שני אלחרר]

ראינו בפעמים הקודמות את הExtension Method – SelectMany שיודעת לשטח IEnumerableים נוספים, וגם הכרנו את הquery syntax של linq.

ניתן להשתמש בquery syntax של linq על SelectMany, הדרך לעשות זאת היא כך :

1
2
3
4
5
IEnumerable<Person> allChildren =
from family in families
from person in family
where person.Age <= 12
select person;

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

1
2
3
IEnumerable<Person> allChildren =
families.SelectMany(persons => persons)
.Where(person => person.Age <= 12);

אבל למעשה, לא כך המצב.

אחרי הfrom השני עדיין יש לנו גישה למשתנה family, כלומר אנחנו יכולים לעשות משהו כזה:

1
2
3
4
5
IEnumerable<Person> allChildren =
from family in families
from person in family
where (person.Age <= 12) && (family.Count() >= 3)
select person;

לכן השאילתא הזאת

1
2
3
4
5
IEnumerable<Person> allChildren =
from family in families
from person in family
where person.Age <= 12
select person;

מתקמפלת בעצם למשהו כזה:

1
2
3
4
5
6
IEnumerable<Person> allChildren =
families.SelectMany
(family => family,
(family, person) => new {family, person})
.Where(pair => pair.person.Age <= 12)
.Select(pair => pair.person);

וזו שציינתי למעלה למשהו כזה:

1
2
3
4
5
6
7
IEnumerable<Person> allChildren =
families.SelectMany
(family => family,
(family, person) => new {family, person})
.Where(pair => (pair.person.Age <= 12) &&
(pair.family.Count() >= 3))
.Select(pair => pair.person);

אני אזכיר שSelectMany הוא Extension Method ומקבל שני delegateים – הראשון קובע איך לייצר IEnumerableים חדשים מאיברים של IEnumerable קיים, והשני קובע איך ליצור איבר מהIEnumerable החדש והאיבר המקורי.

משהו כזה:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>
(this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector)
{
foreach (TSource current in source)
{
foreach (TCollection transform in collectionSelector(current))
{
yieldreturn resultSelector(current, transform);
}
}
}

בשתי הדוגמאות הSelectMany מקבל אותם פרמטרים – מה שהוא עושה זה יוצר IEnumerable חדש של זוגות: איש והמשפחה אליה הוא שייך. שימו לב שהוא משתמש בטיפוסים אנונימיים שהכרנו כבר.

שתף