For your first request, how to implement your own FilteredLookup , able to take advantage of another ILookup ?
(thanks to Jon Skeet for the tip)
public static ILookup<TKey, TElement> ToFilteredLookup<TKey, TElement>(this ILookup<TKey, TElement> lookup, Func<IGrouping<TKey, TElement>, bool> filter) { return new FilteredLookup<TKey, TElement>(lookup, filter); }
With the FilteredLookup class:
internal sealed class FilteredLookup<TKey, TElement> : ILookup<TKey, TElement> { int count = -1; Func<IGrouping<TKey, TElement>, bool> filter; ILookup<TKey, TElement> lookup; public FilteredLookup(ILookup<TKey, TElement> lookup, Func<IGrouping<TKey, TElement>, bool> filter) { this.filter = filter; this.lookup = lookup; } public bool Contains(TKey key) { if (this.lookup.Contains(key)) return this.filter(this.GetGrouping(key)); return false; } public int Count { get { if (count >= 0) return count; count = this.lookup.Where(filter).Count(); return count; } } public IEnumerable<TElement> this[TKey key] { get { var grp = this.GetGrouping(key); if (!filter(grp)) throw new KeyNotFoundException(); return grp; } } public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator() { return this.lookup.Where(filter).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private IGrouping<TKey, TElement> GetGrouping(TKey key) { return new Grouping<TKey, TElement>(key, this.lookup[key]); } }
and grouping:
internal sealed class Grouping<TKey, TElement> : IGrouping<TKey, TElement> { private readonly TKey key; private readonly IEnumerable<TElement> elements; internal Grouping(TKey key, IEnumerable<TElement> elements) { this.key = key; this.elements = elements; } public TKey Key { get { return key; } } public IEnumerator<TElement> GetEnumerator() { return elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
So basically your first request will be:
var germanFamilies = families.ToFilteredLookup(family => IsNameGerman(family.Key));
This avoids re-alignment-filtering-ToLookup or creating a new dictionary (and so on hashing).
For the second query, the idea will be similar, you just need to create a similar class, not filtering for all IGrouping , but for IGrouping elements.
Just an idea, maybe it cannot be faster than other methods :)