How to implement generic dictionary class? - c#

When I try to run the following code, the foreach statement is throwing the below error at compile time
Cannot convert type 'string' to
'System.Collections.Generic.KeyValuePair>'
namespace myClass
{
public class myDictionary<T>
{
Dictionary<string, List<T>> dictionary = new Dictionary<string, List<T>>();
public void Add(string key, T value)
{
List<T> list;
if (this.dictionary.TryGetValue(key, out list))
{
list.Add(value);
}
else
{
list = new List<T>();
list.Add(value);
this.dictionary[key] = list;
}
}
public IEnumerable<string> Keys
{
get
{
return this.dictionary.Keys;
}
}
public List<T> this[string key]
{
get
{
List<T> list;
if (!this.dictionary.TryGetValue(key, out list))
{
list = new List<T>();
this.dictionary[key] = list;
}
return list;
}
}
public IEnumerator<T> GetEnumerator()
{
return (dictionary as IEnumerable<T>).GetEnumerator();
}
}
class Program
{
static void Main()
{
myDictionary<string> dictionary = new myDictionary<string>();
dictionary.Add("One", "AA");
dictionary.Add("One", "BB");
dictionary.Add("Two", "CC");
dictionary.Add("Two", "DD");
foreach(KeyValuePair<string, List<string>> pair in dictionary)
{
}
}
}
}
Please let me know what is wrong with my implementation. Thanks for your help.

It looks like the problem is:
public IEnumerator<T> GetEnumerator()
{
return (dictionary as IEnumerable<T>).GetEnumerator();
}
However, you'll need to clarify what this should return, since your dictionary is one of lists. Is this meant to be all the values from all the lists in turn? If so, I guess:
public IEnumerator<T> GetEnumerator()
{
return dictionary.Values.SelectMany(x => x).GetEnumerator();
}
If, however, you want to return the pairs, then:
public IEnumerator<KeyValuePair<string, List<T>>> GetEnumerator()
{
return dictionary.GetEnumerator();
}

Related

Is there a way to avoid the Cast<T>() if I already have the correct type in the following C# scenario?

public class ItemStore {
private Dictionary<Type, List<object>> _items = new Dictionary<Type, List<object>>();
public void AddItem(object item) {
var type = item.GetType();
if (!_items.ContainsKey(type)) {
_items[type] = new List<object>();
}
_items[type].Add(item);
}
public IEnumerable<T> GetItems<T>() {
if(!_items.ContainsKey(typeof(T))) {
return new List<T>();
}
return _items[typeof(T)].Cast<T>();
}
}
(The real scenario is more complex, and it is a library used in multiple Projects knowing nothing about the concrete types.... )
The Cast<T>() in GetItems() is consuming quite some time. So I would prefere to avoid it. Is there any way to avoid it in C# - because actually the list already contains the correct types?
You need to modify the internal structure of this class a bit to not use generics in the items lookup because we need to underlying type of the stored list to be the correct type. This requires a little reflection when creating the list. We can also make AddItem and GetItems a little more efficient by avoiding extra lookups:
public class ItemStore {
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem(object item) {
var type = item.GetType();
IList list;
if (!_items.TryGetValue(type, out list)) {
var listType = typeof(List<>).MakeGenericType(type);
list = (IList)Activator.CreateInstance(listType);
_items[type] = list;
}
list.Add(item);
}
public IEnumerable<T> GetItems<T>() {
IList list;
if(!_items.TryGetValue(typeof(T), out list)) {
return Enumerable.Empty<T>();
} else {
return (IEnumerable<T>)list;
}
}
}
If you can modify the signature of AddItem this could be even simpler (no reflection), but given you've said this is an over simplification, I will leave the public API unchanged.
Use IList instead of List(T)
Make AddItem() method generic
public class ItemStore
{
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem<T>(T item)
{
var type = typeof(T);
if (!_items.ContainsKey(type))
{
_items[type] = new List<T>();
}
_items[type].Add(item);
}
public IEnumerable<T> GetItems<T>()
{
if (!_items.ContainsKey(typeof(T)))
{
return new List<T>();
}
return (List<T>)_items[typeof(T)];
}
}
You could make your method AddItem generic, which would allow you to store List<T> instances in your dictionary (whose generic TValue parameter should be IList in this case).
public class ItemStore
{
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem<T>(T item)
{
IList objList;
if (!_items.TryGetValue(typeof(T), out objList))
{
objList = new List<T>();
_items[typeof(T)] = objList;
}
objList.Add(item);
}
public IEnumerable<T> GetItems<T>()
{
IList objList;
return
(_items.TryGetValue(typeof(T), out objList)) ? (List<T>)objList
: new List<T>();
}
}

Does such a collection exist (functionality from Dictionary & HashSet)?

I am looking for a collection where no element can exist more than once, and are also indexed. Similar to Dictionary, but without Key, just Value. Similar to a HashSet, but indexed so I can easily retrieve an element without iterating over the collection. I hope this makes sense. :)
You can use a HashSet. It is "indexed", after all, performance would be lacking if it weren't.
Use the Contains method to "retrieve" an element. If you want to remove it as well, use Remove.
Both methods are O(1) operations.
You can use a Dictionary<T, T> for that and insert elements using Add(value, value).
However, that only makes sense if your type properly implements Equals(object) and GetHashCode(). If it doesn't, two different instanced will never be equal and the HashSet<T>'s Contains(T) method already tells you whether you have the element reference of nor.
HashSet class is best for your work. I won't allow duplicate entries.
Note that the HashSet.Add(T item) method returns a bool -- true if the item was added to the collection; false if the item was already present.
Simply you can add an Extension method to throw exception as
public static void AddOrThrow<T>(this HashSet<T> hash, T item)
{
if (!hash.Add(item))
throw new ValueExistingException();
}
The easiest way to do this is make a class that implements IList<T> but uses a List<T> and HashSet<T> internally. You then just have each method act on each collection as needed.
using System;
using System.Collections.Generic;
namespace Example
{
public class UniqueList<T> : IList<T>
{
private readonly List<T> _list;
private readonly HashSet<T> _hashset;
public UniqueList()
{
_list = new List<T>();
_hashset = new HashSet<T>();
}
public UniqueList(IEqualityComparer<T> comparer)
{
_list = new List<T>();
_hashset = new HashSet<T>(comparer);
}
void ICollection<T>.Add(T item)
{
Add(item);
}
public bool Add(T item)
{
var added = _hashset.Add(item);
if (added)
{
_list.Add(item);
}
return added;
}
public void RemoveAt(int index)
{
_hashset.Remove(_list[index]);
_list.RemoveAt(index);
}
public T this[int index]
{
get { return _list[index]; }
set
{
var oldItem = _list[index];
_hashset.Remove(oldItem);
var added = _hashset.Add(value);
if (added)
{
_list[index] = value;
}
else
{
//Put the old item back before we raise a exception.
_hashset.Add(oldItem);
throw new InvalidOperationException("Object already exists.");
}
}
}
public int IndexOf(T item)
{
return _list.IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
Insert(index, item);
}
public bool Insert(int index, T item)
{
var added = _hashset.Add(item);
if (added)
{
_list.Insert(index, item);
}
return added;
}
public void Clear()
{
_list.Clear();
_hashset.Clear();
}
public bool Contains(T item)
{
return _hashset.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
var removed = _hashset.Remove(item);
if (removed)
{
_list.Remove(item);
}
return removed;
}
public int Count
{
get { return _list.Count; }
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I did explicit implementations of Add and Insert so I could give them versions that returned a bool to tell if the operation succeeded or not. I could not return a value in the T this[int index] setter so I have it throw a InvalidOperationException if you attempt to insert a duplicate.
It does not throw if you do ICollection.Add on a duplicate, it just does not add it. This is because that is the behavior HashSet<T>.ICollection<T>.Add has and i wanted to mimic it.

Add Element to Dictionary of Lists

I have
Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();
and at some points I want to add numbers to myDict for a specific Dictionary key.
I am currently doing
if (!myDict.ContainsKey(newKey)){
myDict[newKey] = new List<int>();
}
myDict[newKey].Add(myNumber);
but that seems to be error prone to forgetting the ContainsKey check at some point.
I have searched for a way to make Dictionaries return a new List in case myDict["entry"] doesn't exist yet, but I couldn't find anything.
Here's a relatively simple implementation of the LazyLookup example I mentioned. It only implements IEnumerable out of brevity/simplicity to answer the question.
Essentially, upon accessing an index, it will make sure it has already been initialized to a new instance of the List<T> class.
public class LazyLookup<TKey, TValue> : IEnumerable<List<TValue>>
{
private readonly Dictionary<TKey, List<TValue>> CachedEntries;
private readonly Func<List<TValue>> LazyListCreator;
public LazyLookup()
: this(() => new List<TValue>())
{
}
public LazyLookup(Func<List<TValue>> lazyListCreator)
{
this.LazyListCreator = lazyListCreator;
this.CachedEntries = new Dictionary<TKey, List<TValue>>();
}
public List<TValue> this[TKey key]
{
get
{
return GetOrCreateValue(key);
}
}
private List<TValue> GetOrCreateValue(TKey key)
{
List<TValue> returnValue;
if (!CachedEntries.TryGetValue(key, out returnValue))
{
returnValue = LazyListCreator();
CachedEntries[key] = returnValue;
}
return returnValue;
}
public IEnumerator<List<TValue>> GetEnumerator()
{
return CachedEntries.Values.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
With some usage:
var lazyLookup = new LazyLookup<string, int>();
lazyLookup["nocheck"].Add(9001);
//outputs 9001
Console.WriteLine(lazyLookup["nocheck"][0]);
//outputs 0 as it's a newly initialized list
Console.WriteLine(lazyLookup["someOtherLookup"].Count);
At this point, you could update it to be threadsafe (as GetOrCreateValue currently is not threadsafe), or generalize it so it doesn't assume it's of List<T> but any type, or extend it to implement the full IDictionary<TKey, TValue> interface. But at minimum, if the above pattern you posted is used often, you may consider swapping direct usage of the dictionaries with some encapsulation which trivializes the task for you and eliminates code duplication.
You can use TryGetValue:
List<int> list;
if(!myDict.TryGetValue(newKey, out list))
{
list = new List<int>();
myDict.Add(newKey, list);
}
list.Add(myNumber);
If the Dictionary is a field i would encapsulate the acces in a method:
Dictionary<string, List<int>> myDict = new Dictionary<string, List<int>>();
public void AddNumber(string key, int value)
{
List<int> list;
if(!myDict.TryGetValue(key, out list))
{
list = new List<int>();
myDict.Add(key, list);
}
list.Add(value);
}
If you use ConcurrentDictionary<T>, you can do this:
myDict.GetOrAdd(newKey, new List<int>()).Add(myNumber);
You can actually use the others' suggestions. By encapsulating the access in a method or even using ConcurrentDictionary.
But for me, I would have a custom dictionary so you can actually implement what myDict["entry"] does if it did not see an element.
Good thing with this is you have full control on how you would like this dictionary to behave.
class MyCustomDictionary<TKey, TValue> : IDictionary<TKey, TValue>
where TValue : class, new()
{
private Dictionary<TKey, TValue> _dictionary;
public MyCustomDictionary()
{
_dictionary = new Dictionary<TKey, TValue>();
}
public TValue this[TKey key] // this is what's important
{
get
{
TValue val;
if (!_dictionary.TryGetValue(key, out val)) // if there is no element for that key, add a new element and return it
{
_dictionary.Add(key, new TValue());
return _dictionary[key];
}
else // else return the found element
{
return val;
}
}
set
{
_dictionary[key] = value;
}
}
public void Add(TKey key, TValue value)
{
_dictionary.Add(key, value);
}
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return _dictionary.Keys; }
}
public bool Remove(TKey key)
{
return _dictionary.Remove(key);
}
public bool TryGetValue(TKey key, out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return _dictionary.Values; }
}
public void Add(KeyValuePair<TKey, TValue> item)
{
_dictionary.Add(item.Key, item.Value);
}
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dictionary.ToList().CopyTo(array, arrayIndex); // do you need this? you can leave this :)
}
public int Count
{
get { return _dictionary.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return _dictionary.Remove(item.Key);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictionary.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _dictionary.GetEnumerator();
}
}
Then you use it like:
MyCustomDictionary<string, List<int>> myCustomDict = new MyCustomDictionary<int, List<int>>();
// return a new List of int
var someElementThatIsNotFound = myCustomDict["keyThatIsNonExistent"];
You can use TryGetValue method: if there's the key in the dictionary
you should just add the value into the list; otherwise you should
add a list with a value:
List<int> list
if (myDict.TryGetValue(newKey, out list))
list.Add(myNumber);
else
myDict.Add(newKey, new List<int>() { myNumber });
Lots of good answers already. I implemented an extension method for this exact reason:
public static TVALUE GetOrSet<TKEY, TVALUE>(this IDictionary<TKEY, TVALUE> self,
TKEY key,
Func<TVALUE> defaultValue)
{
TVALUE value;
if (!self.TryGetValue(key, out value))
{
value = defaultValue();
self[key] = value;
}
return value;
} // eo GetOrSet
Note that it takes a function to assign the value if it is not present. Either way, the value will be returned. Usage:
var dict = new Dictionary<string, List<int>>();
List<int> ints = dict.GetOrSet("list1", () => return new List<int>());
ints.Add(1);
If you're not referencing it again, you could potentially be less verbose:
dict.GetOrSet("list1", () => return new List<int>()).Add(1);

IDictionaryEnumerator is not an iterator interface type?

I'm trying to port some code that uses Hashtable to an environment that doesn't have this class. So I thought about not messing with the code and just create my own Hashtable from Dictionary, like this:
public class Hashtable : Dictionary<Object, Object> {
// ...
new public IDictionaryEnumerator GetEnumerator() {
var ie = base.GetEnumerator();
while (ie.MoveNext())
yield return new DictionaryEntry(ie.Current.Key, ie.Current.Value);
}
}
I'm getting this error:
error CS1624: The body of 'System.Collections.Hashtable.GetEnumerator()' cannot be an iterator block because 'System.Collections.IDictionaryEnumerator' is not an iterator interface type
Well, but IDictionaryEnumerator inherits from IEnumerator.
The odd thing is that if I just return (IDictionaryEnumerator)base.GetEnumerator(); the code compiles (but fails during runtime in the foreach loop).
I don't understand what this error is telling me and don't know how to properly implement this.
Iterator blocks are rewritten by the compiler into classes that implement IEnumerable or IEnumerator; the compiler doesn't know how to generate a class that implement IDictionaryEnumerator, so you can't use an iterator block to implement that interface.
A possible workaround is to provide your own implementation of IDictionaryEnumerator:
class Hashtable : Dictionary<object, object>
{
new public IDictionaryEnumerator GetEnumerator()
{
return new DictionaryEnumerator(base.GetEnumerator());
}
struct DictionaryEnumerator : IDictionaryEnumerator
{
private Enumerator _en;
public DictionaryEnumerator(Dictionary<object, object>.Enumerator en)
{
_en = en;
}
public object Current
{
get
{
return Entry;
}
}
public DictionaryEntry Entry
{
get
{
var kvp = _en.Current;
return new DictionaryEntry(kvp.Key, kvp.Value);
}
}
public bool MoveNext()
{
bool result = _en.MoveNext();
return result;
}
public void Reset()
{
throw new NotSupportedException();
}
public object Key
{
get
{
var kvp = _en.Current;
return kvp.Key;
}
}
public object Value
{
get
{
var kvp = _en.Current;
return kvp.Value;
}
}
}
}

Why is Lookup immutable in C#?

Unlike Dictionary, you cannot construct a Lookup by adding elements one by one. Do you happen to know the reason?
Lookup is just like multimap in C++; why can't we modify it in C#? If we really can't, how can we construct a multimap data structure in C#?
Lookup and ILookup were introduced as part of LINQ, which generally takes a more functional approach than other aspects of the framework. Personally I like the fact that Lookup is (at least publicly) immutable - and I'm looking forward to more immutable collections being available.
If you want to create your own multimap data structure, just maintain a Dictionary<TKey, List<TValue>> or something similar. You might want to look at my Edulinq implementation of Lookup for some sample code.
Here is an implementation I wrote
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class MultiLookup<Key, Value> : ILookup<Key, Value>
{
Dictionary<Key, HashSet<Value>> Contents = new Dictionary<Key, HashSet<Value>>();
public void Add(Key key, Value value)
{
if (!Contains(key))
{
Contents[key]=new HashSet<Value>();
}
Contents[key].Add(value);
}
public void Add(IEnumerable<Tuple<Key, Value>> items)
{
foreach (var item in items)
{
Add(item.Item1, item.Item2);
}
}
public void Remove(Key key, Value value)
{
if (!Contains(key))
{
return;
}
Contents[key].Remove(value);
if (Contents[key].Count==0)
{
Contents.Remove(key);
}
}
public void RemoveKey(Key key)
{
Contents.Remove(key);
}
public IEnumerable<Key> Keys
{
get
{
return Contents.Keys;
}
}
public int Count
{
get
{
return Contents.Count;
}
}
public bool Contains(Key key)
{
return Contents.ContainsKey(key);
}
private class Grouping : IGrouping<Key, Value>
{
public MultiLookup<Key, Value> _source;
public Key _key;
public Key Key
{
get { return _key; }
}
public static HashSet<Value> Empty = new HashSet<Value>();
public IEnumerator<Value> GetEnumerator()
{
if (!_source.Contains(_key))
{
yield break;
}
else
{
foreach (var item in _source[_key])
{
yield return item;
}
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public IEnumerator<IGrouping<Key, Value>> GetEnumerator()
{
return (from p in Contents
select new Grouping() { _key = p.Key, _source = this }).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerable<Value> this[Key key]
{
get { return Contents[key]; }
}
}
and a test case ( probably not exhaustive ) for you
using FluentAssertions;
using System.Linq;
using Xunit;
public class MultiLookupSpec
{
MultiLookup<int, string> Fixture = new MultiLookup<int,string>();
[Fact]
public void NewLookupShouldBeEmpty()
{
Fixture.Count.Should().Be(0);
}
[Fact]
public void AddingANewValueToANonExistentKeyShouldCreateKeyAndAddValue()
{
Fixture.Add(0, "hello");
Fixture.Count.Should().Be(1);
}
[Fact]
public void AddingMultipleValuesToAKeyShouldGenerateMultipleValues()
{
Fixture.Add(0, "hello");
Fixture.Add(0, "cat");
Fixture.Add(0, "dog");
Fixture[0].Should().BeEquivalentTo(new []{"hello", "cat", "dog"});
}
[Fact]
public void RemovingAllElementsOfKeyWillAlsoRemoveKey()
{
Fixture.Add(0, "hello");
Fixture.Add(0, "cat");
Fixture.Add(0, "dog");
Fixture.Remove(0, "dog");
Fixture.Remove(0, "cat");
Fixture.Remove(0, "hello");
Fixture.Contains(0).Should().Be(false);
}
[Fact]
public void EnumerationShouldWork()
{
Fixture.Add(0, "hello");
Fixture.Add(0, "cat");
Fixture.Add(0, "dog");
Fixture.Add(1, "house");
Fixture.Add(2, "pool");
Fixture.Add(2, "office");
Fixture.Select(s => s.Key).Should().Contain(new[] { 0, 1, 2 });
Fixture.SelectMany(s => s).Should().Contain(new[] { "hello", "cat", "dog", "house", "pool", "office" });
}
}
I had this same problem and question. Why is Lookup immutable? I solved it with some extension methods to IDictionary
public static void Add<TKey,TList,TItem>(this IDictionary<TKey,TList> dict,TKey key,TItem item)
where TList : ICollection<TItem>,new()
{
if(!dict.ContainsKey(key))
{
dict.Add(key, new TList());
}
dict[key].Add(item);
}
public static void Remove<TKey, TList, TItem>(this IDictionary<TKey, TList> dict, TKey key)
where TList : IEnumerable<TItem>, new()
{
if (dict.ContainsKey(key))
{
dict.Remove(key);
}
}
public static TList Items<TKey, TList, TItem>(this IDictionary<TKey, TList> dict, TKey key)
where TList : IEnumerable<TItem>, new()
{
if (dict.ContainsKey(key))
{
return dict[key];
}
return default(TList);
}

Categories