LINQ aggregating multiple IEnumerables into one?
I have a Dictionary defined as <int, IEnumerable<char>>
. Lets say the data is populated like:
1, a b c d e
2, f g h i j
3, k l m n o
开发者_JS百科
If I have an IEnumerable consisting of 1 & 3, what would the LINQ look like to return 'a b c d e k l m n o'
(assuming space represents an iteration).
SelectMany is indeed what you want, but IMHO it's more readable to use the comprehension syntax and let it do the mapping for you, so something like:
var dict = ... // dictionary
var keys = ... // enumerable with 1 and 3 in it
var result = from key in keys
from val in dict[key]
select val;
It's easier (again, IMHO) to toss an 'orderby' in there as well if/as needed.
Of course, if you find the extension method version simpler to read/parse, then by all means, use that instead. :)
If you want a KeyNotFoundException if a key is not found:
IEnumerable<char> result = keys.SelectMany(key => d[key]);
If you want to silently ignore keys that are not found:
IEnumerable<char> result = keys.Where(key => d.ContainsKey(key))
.SelectMany(key => d[key]);
Assuming that you have
var someEnumerables = new Dictionary<int, IEnumerable<char>>();
then
// Flattened will be an enumeration of the values ordered first by the key
var flattened = someEnumerables.OrderBy(kvp => kvp.Key).SelectMany(kvp => kvp.Value)
As you mentioned in your comment, you can use a SelectMany
to aggregate an IEnumerable
of IEnumerable
s into a single IEnumerable
. However, you can also use Concat
to combine two separate collections into a single selection (or you can chain it to combine as many as you'd like).
You need a Where
clause to filter the keys contained in the dictionary, and a SelectMany
clause to get a single enumerable list from each list contained in the dictionary.
Dictionary<int, IEnumerable<char>> dict; // contains all of your key-value pairs
IEnumerable<int> keys; // contains the keys you want to filter by
IEnumerable<char> data = dict.Where(kvp => keys.Contains(kvp.Key))
.SelectMany(kvp => kvp.Value);
// or, alternatively:
IEnumerable<char> data = keys.SelectMany(i => dict[i]);
Note that the second query will throw an exception if you have a key in the keys
enumerable that doesn't exist in your dictionary.
It's unclear if you want only the 1 & 3 lines or all of them (1, 2 and 3). Here's the solution for both
Dictionary<int, string> map = ...;
// 1 and 3 only
IEnumerable<char> result1 = map
.Where(x => x.Key == 1 || x.Key == 3)
.OrderyBy(x => x.Key)
.SelectMany(x => x.Value)
// All
IEnumerable<char> result2 = map
.OrderyBy(x => x.Key)
.SelectMany(x => x.Value)
精彩评论