开发者

LINQ aggregating multiple IEnumerables into one?

开发者 https://www.devze.com 2023-04-08 14:55 出处:网络
I have a Dictionary defined as <int, IEnumerable<char>>.Lets say the data is populated like:

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 IEnumerables 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)
0

精彩评论

暂无评论...
验证码 换一张
取 消