Skip to content

Instantly share code, notes, and snippets.

@weitzhandler
Last active September 17, 2021 14:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weitzhandler/ee19db3b6dc21580d9296f86bfbb1e06 to your computer and use it in GitHub Desktop.
Save weitzhandler/ee19db3b6dc21580d9296f86bfbb1e06 to your computer and use it in GitHub Desktop.
MultiValueDictionary<TKey, TValue>
namespace System.Collections.ObjectModel
{
using System.Collections.Generic;
using System.Linq;
public class MultiValueDictionary<TKey, TElement>
: Collection<TElement>, ILookup<TKey, TElement>
{
public MultiValueDictionary(Func<TElement, TKey> keyExtractor)
: base(new Collection(keyExtractor))
{
}
new Collection Items => (Collection)base.Items;
public IEnumerable<TElement> this[TKey key] => Items[key];
public bool Contains(TKey key) => Items.Contains(key);
IEnumerator<IGrouping<TKey, TElement>>
IEnumerable<IGrouping<TKey, TElement>>.GetEnumerator() => Items.GetEnumerator();
class Collection
: KeyedCollection<TKey, Grouping>, IList<TElement>
{
Func<TElement, TKey> KeyExtractor { get; }
public Collection(Func<TElement, TKey> keyExtractor) => KeyExtractor = keyExtractor;
protected override TKey GetKeyForItem(Grouping item) => item.Key;
public void Add(TElement item)
{
var key = KeyExtractor(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
collection.Add(item);
else
Add(new Grouping(key) { item });
}
public bool Remove(TElement item)
{
var key = KeyExtractor(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)
&& collection.Remove(item))
{
if (collection.Count == 0)
Remove(key);
return true;
}
return false;
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
{
foreach (var group in base.Items)
foreach (var item in group)
yield return item;
}
Exception IndexError() => new NotSupportedException("Indexing not supported.");
public int IndexOf(TElement item) => throw IndexError();
public void Insert(int index, TElement item) => Add(item);
public bool Contains(TElement item) => Items.Contains(item);
public void CopyTo(TElement[] array, int arrayIndex) => throw IndexError();
new IEnumerable<TElement> Items => this;
public bool IsReadOnly => false;
TElement IList<TElement>.this[int index]
{
get => throw IndexError();
set => throw IndexError();
}
}
class Grouping : Collection<TElement>, IGrouping<TKey, TElement>
{
public Grouping(TKey key) => Key = key;
public TKey Key { get; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment