280. ToDictionary extension method

לפעמים יש לנו איזשהו אוסף ואנחנו מעוניינים ליצור איזשהו Dictionary ממנו.

דוגמה אחת היא הדוגמה שראינו פעם קודמת:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ICollection<Tuple<string, int>> keys = stateAndIdToName.Keys;
IEnumerable<int> israeliIds =
from key in keys
where key.Item1 == "Isreal"
select key.Item2;
Dictionary<int, string> isrealiIdToName =
new Dictionary<int, string>();
foreach (int israeliId in israeliIds)
{
isrealiIdToName[israeliId] =
stateAndIdToName["Israel", israeliId];
}

למרבה המזל, לא חייבים לעבוד כל כך קשה כדי ליצור Dictionary כזה. בSystem.Linq יש Extension Method לIEnumerable<T> בשם ToDictionary שמאפשר לנו ליצור Dictionary בצורה פשוטה ע"י העברת שני Delegate – הראשון בוחר מפתח, והשני בוחר ערך.

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

זה נראה בערך ככה:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static Dictionary<TKey, TValue> ToDictionary<TSource, TKey, TValue>
(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TValue> valueSelector)
{
Dictionary<TKey, TValue> result = new Dictionary<TKey, TValue>();
foreach (TSource current insource)
{
result.Add(keySelector(current), valueSelector(current));
}
return result;
}

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

1
2
3
Dictionary<int,string> isrealiIdToName =
israeliIds.ToDictionary(id => id,
id => stateAndIdToName["Israel", id]);

יותר יפה 😃

זה מאוד שימושי כשרוצים לבנות משאילתת LINQ איזשהו Dictionary, ע"י שילוב עם Anonymous types:

למשל, נניח שיש לנו רשימה של שמות מלאים של אנשים בצירוף איזושהי קידומת:

1
2
3
4
5
6
7
8
9
10
11
12
13
IEnumerable<string> bandsMembers =
new[]
{
@"Queen\Brian May",
@"Queen\Roger Taylor",
@"Queen\Freddie Mercury",
@"Queen\John Deacon",
@"Scorpions\Klaus Meine",
@"Scorpions\Rudolf Schenker",
@"Scorpions\Paweł Mąciwoda",
@"Scorpions\James Kottak",
@"Scorpions\Matthias Jabs"
};

ואנחנו מעוניינים למפות שמות של אנשים לקידומת שלהם. נוכל ליצור שאילתת LINQ וליצור ממנה Dictionary 😃:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var membersAndBands =
from member in bandsMembers
let seperator = member.IndexOf(@"\")
let bandName = member.Substring(0, seperator)
let name = member.Substring(seperator + 1)
select new
{
BandName = bandName,
Name = name
};
Dictionary<string, string> memberToBand =
membersAndBands.ToDictionary(x => x.Name,
x => x.BandName);

ככה אנחנו משתמשים בAnonymous Type רק כתווך זמני לעיבוד.

ראו גם טיפים על LINQ ואת טיפ מספר 90.

המשך יום למילון טוב

שתף