I have a bit of a complex dictionary.
It's a dictionary which holds two enumerated types & a List<>
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary;
So when I want to use it, I do something like this:
//Add "myString" to the List<string>
myDictionary[BiomeType.Jungle][LocationType.City1].Add("myString"));
When I try to add "myString" to myList, it throws an obvious & foreseeable error: "KeyNotFoundException: The given key was not present in the dictionary."
Is there any way in C# to automatically have the Dictionary add the Key if it isn't already there? I have a lot of BiomeTypes & even more LocationTypes. It would be a PITA to have to create each List, then create each locationtype dictionary, and then to add it for every BiomeType. All that work just to initialize this complex dictionary. Is there no easy way to do this?
I'm using this for gamedev, to store objects in a Dictionary, so I can access them by doing something like
BiomeType playerCurrentBiomeType;
LocationType playerCurrentLocationType;
LoadLevel(myDictionary[playerCurrentBiomeType][playerCurrentLocationType]);
//ex. myDictionary[BiomeType.Jungle][LocationType.CapitalCity]
//ex. myDictionary[BiomeType.Desert][LocationType.CapitalCity]
//ex. myDictionary[BiomeType.Desert][LocationType.City3]
Perhaps, you can try this:
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary = new Dictionary<BiomeType, Dictionary<LocationType, List<string>>>();
BiomeType playerCurrentBiomeType;
LocationType playerCurrentLocationType;
if(!myDictionary.ContainsKey(playerCurrentBiomeType))
{
myDictionary.Add(playerCurrentBiomeType, new Dictionary<LocationType , List<string>>{{playerCurrentLocationType, new List<string>()}});
}
myDictionary[playerCurrentBiomeType][playerCurrentLocationType].Add("bla");
You could do this (although to be honest I'm not sure you should!)
The class below is a type that generally acts like a dictionary, does what you asked for, and has some other changes to hide from you the empty items it creates every time you ask the indexer for an item that doesn't exist.
public class SmellyDictionary<T1, T2>: IDictionary<T1, T2>, ICollection where T2 : ICollection, new()
{
private readonly IDictionary<T1, T2> _dict = new Dictionary<T1, T2>();
public T2 this[T1 key]
{
get
{
T2 value;
if (!_dict.TryGetValue(key, out value))
_dict[key] = value = new T2(); // This stinks!
return value;
}
set { _dict[key] = value; }
}
public bool Contains(KeyValuePair<T1, T2> item)
{
return _dict.Contains(item);
}
public bool ContainsKey(T1 key)
{
return _dict.ContainsKey(key) && _dict[key].Count > 0; // This hides the smell
}
public int Count { get { return _dict.Count(kvp => kvp.Value.Count > 0); } } // This hides the smell
public void Add(T1 key, T2 value)
{
T2 currentValue;
if (_dict.TryGetValue(key, out currentValue) && currentValue.Count > 0)
throw new ArgumentException("A non empty element with the same key already exists in the SmellyDictionary");
_dict[key] = value;
}
public void Add(KeyValuePair<T1, T2> item)
{
Add(item.Key, item.Value);
}
public bool Remove(T1 key)
{
return _dict.Remove(key);
}
public bool Remove(KeyValuePair<T1, T2> item)
{
return _dict.Remove(item);
}
public bool TryGetValue(T1 key, out T2 value)
{
return _dict.TryGetValue(key, out value);
}
public ICollection<T1> Keys { get { return _dict.Keys; } }
public ICollection<T2> Values { get { return _dict.Values; } }
public object SyncRoot { get { return ((ICollection)_dict).SyncRoot; } }
public bool IsSynchronized { get { return ((ICollection)_dict).IsSynchronized; } }
public IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
{
return _dict.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Clear()
{
_dict.Clear();
}
public void CopyTo(Array array, int index)
{
_dict.CopyTo((KeyValuePair<T1, T2>[])array, index);
}
public void CopyTo(KeyValuePair<T1, T2>[] array, int arrayIndex)
{
_dict.CopyTo(array, arrayIndex);
}
public bool IsReadOnly { get { return _dict.IsReadOnly; } }
}
Here's a slightly more sensible option. Just call this method to add a string to your dictionary.
private void AddCityToDictionary(Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary, BiomeType biome, LocationType location, string city)
{
Dictionary<LocationType, List<string>> locationDictionary;
if (!myDictionary.TryGetValue(biome, out locationDictionary))
locationDictionary = myDictionary[biome] = new Dictionary<LocationType, List<string>>();
List<string> cityList;
if (!locationDictionary.TryGetValue(location, out cityList))
cityList = locationDictionary[location] = new List<string>();
cityList.Add(city);
}
Simply looping through every possible enum type & adding in a new value works to fully populate this multi-dimensional dictionary.
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary = new Dictionary<BiomeType, Dictionary<LocationType, List<string>>>(); //No thanks to troll users like Peter.
foreach (BiomeType biomeType in System.Enum.GetValues(typeof(BiomeType)))
{
Dictionary<LocationType, List<string>> newLocDict = new Dictionary<LocationType, List<string>>(); //No thanks to troll users like Peter.
foreach (LocationType locType in System.Enum.GetValues(typeof(LocationType)))
{
List<string> newList = new List<string>();
newLocDict.Add(locType, newList); //Add the final bit here & voila! Finished! No thanks to troll users like Peter.
}
myDictionary.Add(biomeType, newLocDict);
}
Robyn's solution works the same way if you don't want to fully populate the container with ALL enum values.
Related
I kept googling for some time, and I found that the best way that enables you to have a list containing variables with a corresponding unique key is a HashTable or a Dictionary, but I didn't find anything that enables you to have automatic keys(of type integer). I want to call a function that adds an object(passed as a parameter) to the dictionary and returns the automatically generated key(int), and without any key duplicates. How could I accomplish this? I am completely struggling!
EDIT: To clarify things up. This is a server, and I want to assign a unique key for each client. If I use the maximum key value, this value will soon get to the int maximum value on large servers. Because if a client connects then disconnects he leaves behind an unused value which should be reused in order to avoid reaching a very high key maximum value.
The following should do and it reuses freed up keys:
internal class AutoKeyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
private readonly Dictionary<TKey, TValue> inner;
private readonly Func<TKey, TKey> incrementor;
private readonly Stack<TKey> freeKeys;
private readonly TKey keySeed;
private TKey currentKey;
public AutoKeyDictionary(TKey keySeed, Func<TKey, TKey> incrementor)
{
if (keySeed == null)
throw new ArgumentNullException("keySeed");
if (incrementor == null)
throw new ArgumentNullException("incrementor");
inner = new Dictionary<TKey, TValue>();
freeKeys = new Stack<TKey>();
currentKey = keySeed;
}
public TKey Add(TValue value) //returns the used key
{
TKey usedKey;
if (freeKeys.Count > 0)
{
usedKey = freeKeys.Pop();
inner.Add(usedKey, value);
}
else
{
usedKey = currentKey;
inner.Add(usedKey, value);
currentKey = incrementor(currentKey);
}
return usedKey;
}
public void Clear()
{
inner.Clear();
freeKeys.Clear();
currentKey = keySeed;
}
public bool Remove(TKey key)
{
if (inner.Remove(key))
{
if (inner.Count > 0)
{
freeKeys.Push(key);
}
else
{
freeKeys.Clear();
currentKey = keySeed;
}
return true;
}
return false;
}
public bool TryGetValue(TKey key, out TValue value) { return inner.TryGetValue(key, out value); }
public TValue this[TKey key] { get {return inner[key];} set{inner[key] = value;} }
public bool ContainsKey(TKey key) { return inner.ContainsKey(key); }
public bool ContainsValue(TValue value) { return inner.ContainsValue (value); }
public int Count { get{ return inner.Count; } }
public Dictionary<TKey,TValue>.KeyCollection Keys { get { return inner.Keys; } }
public Dictionary<TKey, TValue>.ValueCollection Values { get { return inner.Values; } }
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return inner.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)inner).GetEnumerator(); }
}
Disclaimer: I haven't tested this code, it could have a few pesty bugs of little importance, the general approach is sound.
Write a class which does this. Something like this:
class AutoIndexDictionary : IEnumerable<Whatever>
{
private readonly Dictionary<int, Whatever> myDict = new Dictionary<int, Whatever>();
private int currentIndex = 0;
public int Add(Whatever item)
{
var myIndex = currentIndex
myDict.Add(myIndex, item);
currentIndex ++;
return myIndex;
}
public void Remove(int index)
{
myDict.Remove(index);
}
// implement IEnumerable, indexer etc.
// ...
}
Create a method that gets the max key value from the dictionary using LINQ, adds 1 to it and then uses that as the key for the value you would like to add, like this:
public void AddToMyDictionary(string value)
{
int NextKey = MyDictionary.Keys.Max() + 1;
MyDictionary.Add(NextKey, value);
}
Obviously, this assumes your dictionary is a Dictionary<int, string>, but you can obviously modify for your purposes.
If you want to re-use keys that have been removed, store the next index when something is added / removed.
private int NextKey = 0;
public int AddToMyDictionary(string value)
{
int currentKey = NextKey;
MyDictionary.Add(currentKey, value);
NextKey = MyDictionary.Keys.Max() + 1;
return currentKey;
}
public void RemoveFromMyDictionary(int key)
{
MyDictionary.Remove(key);
NextKey = key;
}
This is what int Object.GetHashCode() is for.
Wouldn't a List do what you say, without any additional overhead? You call it a "unique integer key", but in List terminology, that's simply called an "index".
If you really wanted a custom function to add a value and get a key all in one step, you could inherit from List<T>, like so:
class MyCustomList<T> : List<T>
{
//Not thread-safe
public int AddAndGetKey(T valueToAdd)
{
Add(valueToAdd);
return LastIndexOf(valueToAdd);
}
}
I use LastIndexOf() because the list may include duplicate values and adding to the list always adds to the end. So this should work unless you get into multithreaded situations where you'd have to add-and-get-index in one atomic operation. (Alternately maybe you could add an extension method to List<T>.)
The advantage of using a List is that there would be no gaps in keys. On the flipside, removing an item in the middle would change the key of every item after it. But I guess it depends what behavior you're looking for.
Given the additional information provided in your edit then i don't think int is the correct datatype for you, you shouldn't reuse ID's the way you are describing as if a client with an ID gets disconnected but don't realise then you could have 1 ID in use by 2 clients. change your datatype to Guid then when you get a new client give it a key of Guid.NewGuid() and the chance of duplicate keys drops as close as possible to 0
I like Stefan Steinegger's solution. Here is an alternative that uses a List<> behind the scenes, but ensures the List<> is never removed from:
class AutoKeyDictionary<TValue> : IEnumerable<TValue> where TValue : class
{
readonly List<TValue> list = new List<TValue>();
public int Add(TValue val)
{
if (val == null)
throw new ArgumentNullException(nameof(val), "This collection will not allow null values.");
list.Add(val);
return list.Count - 1;
}
public void RemoveAt(int key)
{
// do not remove ('list.Count' must never decrease), overwrite with null
// (consider throwing if key was already removed)
list[key] = null;
}
public TValue this[int key]
{
get
{
var val = list[key];
if (val == null)
throw new ArgumentOutOfRangeException(nameof(key), "The value with that key is no longer in this collection.");
return val;
}
}
public int NextKey => list.Count;
public int Count => list.Count(v => v != null); // expensive O(n), Linq
public bool ContainsKey(int key) => key >= 0 && key < list.Count && list[key] != null;
public TValue TryGetValue(int key) => (key >= 0 && key < list.Count) ? list[key] : null;
public void Clear()
{
for (var i = 0; i < list.Count; ++i)
list[i] = null;
}
public IEnumerator<TValue> GetEnumerator() => list.Where(v => v != null).GetEnumerator(); // Linq
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int FirstKeyOf(TValue val) => list.IndexOf(val);
public IDictionary<int, TValue> ToDictionary()
{
var retColl = new SortedList<int, TValue>(list.Count);
for (var i = 0; i < list.Count; ++i)
{
var val = list[i];
if (val != null)
retColl.Add(i, val);
}
return retColl;
}
// and so on...
}
Not thread-safe, obviously.
Be aware, the same value can be present several times in the collection, but with different keys.
I have a reference to an object. I know it conforms to
IDictionary<string, T>
for some type T. (It may not conform to plain IDictionary, or to IReadyOnlyDictionary). All I know about T is that it descends from object. How can I get its keys, and get the value for a key? (I am fine with having the value be returned as an object, not as a T. I am also fine with never learning what T is.)
What I want to write, but can't, is something like this:
public void SomeMethod(object reallyADict) { // reallyADict implements IDictionary<string, T>.
foreach (string key in reallyADict.Keys) {
object value = reallyADict[key];
// . . .
}
}
**
Per request, a sample class is below.
using System;
using System.Collections.Generic;
using System.Collections;
namespace My.Collections
{
public class WrappedDictionary: IDictionary<string, int>
{
public WrappedDictionary() {
this.InnerDictionary = new Dictionary<string, int>{ {"one", 1}, {"two", 2 }};
}
private Dictionary<string, int> InnerDictionary { get; set;}
private ICollection<KeyValuePair<string, int>> InnerCollection {
get {
return this.InnerDictionary;
}
}
#region IDictionary implementation
void IDictionary<string, int>.Add(string key, int value) {
this.InnerDictionary.Add(key, value);
}
bool IDictionary<string, int>.ContainsKey(string key) {
return this.InnerDictionary.ContainsKey(key);
}
bool IDictionary<string, int>.Remove(string key) {
return this.InnerDictionary.Remove(key);
}
bool IDictionary<string, int>.TryGetValue(string key, out int value) {
return this.InnerDictionary.TryGetValue(key, out value);
}
int IDictionary<string, int>.this[string index] {
get {
return this.InnerDictionary[index];
}
set {
this.InnerDictionary[index] = value;
}
}
ICollection<string> IDictionary<string, int>.Keys {
get {
return this.InnerDictionary.Keys;
}
}
ICollection<int> IDictionary<string, int>.Values {
get {
return this.InnerDictionary.Values;
}
}
#endregion
#region ICollection implementation
void ICollection<KeyValuePair<string, int>>.Add(KeyValuePair<string, int> item) {
this.InnerCollection.Add(item);
}
void ICollection<KeyValuePair<string, int>>.Clear() {
this.InnerDictionary.Clear();
}
bool ICollection<KeyValuePair<string, int>>.Contains(KeyValuePair<string, int> item) {
return this.InnerCollection.Contains(item);
}
void ICollection<KeyValuePair<string, int>>.CopyTo(KeyValuePair<string, int>[] array, int arrayIndex) {
this.InnerCollection.CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<string, int>>.Remove(KeyValuePair<string, int> item) {
return this.InnerCollection.Remove(item);
}
int ICollection<KeyValuePair<string, int>>.Count {
get {
return this.InnerCollection.Count;
}
}
bool ICollection<KeyValuePair<string, int>>.IsReadOnly {
get {
return this.InnerCollection.IsReadOnly;
}
}
#endregion
#region IEnumerable implementation
IEnumerator<KeyValuePair<string, int>> IEnumerable<KeyValuePair<string, int>>.GetEnumerator() {
return this.InnerCollection.GetEnumerator();
}
#endregion
#region IEnumerable implementation
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return (this as IEnumerable).GetEnumerator();
}
#endregion
}
}
Unfortunatly you cannot cast the reallyADict to something like Dictionary<string,T>, because you need a specific type.
And Manfred's comment to use a generic method like
public IEnumerable<T> SomeMethod<T>(Dictionary<string, T> dict)
would be my approach, too. But you stated you really only have the dictionary as object.
So I solved this with Reflection:
public IEnumerable<object> SomeMethod(object reallyADict)
{
Type genericInterface = reallyADict?.GetType().GetInterface("IDictionary`2");
PropertyInfo propKeys = genericInterface?.GetProperty("Keys");
if (propKeys?.GetMethod == null) yield break;
IEnumerable<string> keys = (IEnumerable<string>)propKeys.GetValue(reallyADict);
PropertyInfo propIndex = genericInterface.GetProperty("Item");
if (propIndex?.GetMethod == null) yield break;
foreach (string key in keys)
yield return propIndex.GetMethod.Invoke(reallyADict, new object[] { key });
}
This method gets the Keys property from the reallyDict (if there is one) and uses it as an IEnumerable<string>.
Then it iterates over all those keys and uses the indexer property of the underlying dictionary to return the value. The indexer property has the name Item.
Each key is unique in the list. When a new key-value pair arrives, the pair is inserted into the list in the ascending order of value (if key already exists then updates the value).
Please avoid sorting the list for every insertion.
I would suggest SortedDictionary or SortedList
As per MSDN :
SortedList uses less memory than SortedDictionary.
SortedDictionary has faster insertion and removal
operations for unsorted data: O(log n) as opposed to O(n) for
SortedList.
Update : After comments
You will have to order the value by yourself for e.g using a dictioanry
var dictionary = new Dictionary<int, string>{ {1, "Z"}, {2, "A"}};
IOrderedEnumerable<KeyValuePair<int, string>> orderedEnumerable = dictionary.OrderBy(d => d.Value);
You aren't going to get a built in component with this behaviour, it's too non-standard. I'd be looking at why and when I needed these competing behaviours. Effectively you are looking at an alternate key. Short of just writing some for of linked list, off the top of my head, I'd look at SortedList for the by value part of it, and a Dictionary for key.
e.g.
a Dictionary of CustomerID and SortKey and a SortedList of SortKey and value.
I'd try and avoid it if I could on the baiss that maintaining both would cost more than simply returning a list of values in the required order on those occasions when you needed it.
If sorting the items for every enumeration is acceptable, you can use a Dictionary<TKey, TValue> and order the key-value pairs by value when you enumerate it:
var dict = new Dictionary<MyKey, MyValue>();
// insertion (updates value when key already exists)
dict[key] = value;
// enumeration (ordered by value)
foreach (var keyValuePair in dict.OrderBy(kvp => kvp.Value))
{
...
}
I would write an ad-hoc class like the following (not completely tested):
public class DictionarySortedByValue<TKey, TValue> : IDictionary<TKey, TValue>
{
class ValueWrapper : IComparable, IComparable<ValueWrapper>
{
public TKey Key { get; private set; }
public TValue Value { get; private set; }
public ValueWrapper(TKey k, TValue v)
{
this.Key = k;
this.Value = v;
}
public int CompareTo(object obj)
{
if (!(obj is ValueWrapper))
throw new ArgumentException("obj is not a ValueWrapper type object");
return this.CompareTo(obj as ValueWrapper);
}
public int CompareTo(ValueWrapper other)
{
int c = Comparer<TValue>.Default.Compare(this.Value, other.Value);
if (c == 0)
c = Comparer<TKey>.Default.Compare(this.Key, other.Key);
return c;
}
}
private SortedSet<ValueWrapper> orderedElements;
private SortedDictionary<TKey, TValue> innerDict;
public DictionarySortedByValue()
{
this.orderedElements = new SortedSet<ValueWrapper>();
this.innerDict = new SortedDictionary<TKey, TValue>();
}
public void Add(TKey key, TValue value)
{
var wrap = new ValueWrapper(key, value);
this.innerDict.Add(key, value);
this.orderedElements.Add(wrap);
}
public bool ContainsKey(TKey key)
{
return this.innerDict.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return this.innerDict.Keys; }
}
public bool Remove(TKey key)
{
TValue val;
if (this.TryGetValue(key, out val))
{
var wrap = new ValueWrapper(key, val);
this.orderedElements.Remove(wrap);
this.innerDict.Remove(key);
return true;
}
return false;
}
public bool TryGetValue(TKey key, out TValue value)
{
return this.innerDict.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return this.innerDict.Values; }
}
public TValue this[TKey key]
{
get
{
return this.innerDict[key];
}
set
{
bool removed = this.Remove(key);
this.Add(key, value);
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
this.Add(item.Key, item.Value);
}
public void Clear()
{
this.innerDict.Clear();
this.orderedElements.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
var wrap = new ValueWrapper(item.Key,item.Value);
return this.orderedElements.Contains(wrap);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
this.innerDict.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this.innerDict.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
if (this.Contains(item))
return this.Remove(item.Key);
return false;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (var el in this.orderedElements)
yield return new KeyValuePair<TKey, TValue>(el.Key, el.Value);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Notes :
it requires that also the TKey type implements IComparable.
the posted code uses only the default Comparer for TKey, and TValue, but
you could pass a custom one through another constructor.
I'm devising a template language. In it, there are 3 kinds of tokens: tags, directives, and variables. Each of these tokens have a name, and there's getting to be quite a few of them. They're extensible too.
To allow name reuse I want to add namespaces.
Right now all the variables are just stored in a dict. The key is the variable name, and the value is the variable value. That way I can quickly retrieve the value of a variable. However, supposing I want to allow dot-notation, namespace.variable, how can I store these variables, such that the namespace is optional? If the namespace is included the dict should only scan that namespace, if not, I guess it scans all namespaces.
Is there a container that will do this?
You should structure your symbol data internally as a dictionary of dictionary of string. The top level dictionary is for namespaces, and each dictionary below each namespace name is the container for all symbols in that namespace.
Looking up an unqualified symbol is simply a matter of looking for the symbol in each namespace in a particular order. In C# or Delphi, the order is determined by the order in which the namespaces are declared at the top of the source file, in reverse order of declaration (most recent is the first to be searched).
You can create your own implementation of IDictionary<string, object> instead of using the framework's Dictionary<TKey, TValue>.
Externally, there would be no change to the way you are consuming it.
Internally, it would consist of a Dictionary<string, Dictionary<string, object>>.
So, if your dictionary is asked for the value matching key "namespace.variable", internally it would split that string, get the Dictionary<string, Dictionary<string, object>> with key "namespace" and then return the value in that Dictionary<string, object> for key "variable."
To make the namespace optional, you have one entry where the key is string.Empty. Whether adding or getting items, any time a key is provided that does not contain ., you'll use the entry with key string.Empty.
My solution:
Class
public class NamespaceDictionary<T> : IDictionary<string, T>
{
private SortedDictionary<string, Dictionary<string, T>> _dict;
private const char _separator = '.';
public NamespaceDictionary()
{
_dict = new SortedDictionary<string, Dictionary<string, T>>();
}
public NamespaceDictionary(IEnumerable<KeyValuePair<string, T>> collection)
: this()
{
foreach (var item in collection)
Add(item);
}
#region Implementation of IEnumerable
public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
{
return _dict.SelectMany(x => x.Value).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
private static Tuple<string, string> Split(string name)
{
int pos = name.LastIndexOf(_separator);
string ns = pos == -1 ? "" : name.Substring(0, pos);
string var = name.Substring(pos + 1);
return new Tuple<string, string>(ns, var);
}
#region Implementation of ICollection<KeyValuePair<string,TValue>>
public void Add(KeyValuePair<string, T> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
_dict.Clear();
}
public bool Contains(KeyValuePair<string, T> item)
{
throw new NotImplementedException();
}
public void CopyTo(KeyValuePair<string, T>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, T> item)
{
return Remove(item.Key);
}
public int Count
{
get { return _dict.Sum(p => p.Value.Count); }
}
public bool IsReadOnly
{
get { return false; }
}
#endregion
#region Implementation of IDictionary<string,TValue>
public bool ContainsKey(string name)
{
var tuple = Split(name);
return ContainsKey(tuple.Item1, tuple.Item2);
}
public bool ContainsKey(string ns, string key)
{
if (ns == "")
return _dict.Any(pair => pair.Value.ContainsKey(key));
return _dict.ContainsKey(ns) && _dict[ns].ContainsKey(key);
}
public void Add(string name, T value)
{
var tuple = Split(name);
Add(tuple.Item1, tuple.Item2, value);
}
public void Add(string ns, string key, T value)
{
if (!_dict.ContainsKey(ns))
_dict[ns] = new Dictionary<string, T>();
_dict[ns].Add(key, value);
}
public bool Remove(string ns, string key)
{
if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key))
{
if (_dict[ns].Count == 1) _dict.Remove(ns);
else _dict[ns].Remove(key);
return true;
}
return false;
}
public bool Remove(string key)
{
var tuple = Split(key);
return Remove(tuple.Item1, tuple.Item2);
}
public bool TryGetValue(string name, out T value)
{
var tuple = Split(name);
return TryGetValue(tuple.Item1, tuple.Item2, out value);
}
public bool TryGetValue(string ns, string key, out T value)
{
if (ns == "")
{
foreach (var pair in _dict)
{
if (pair.Value.ContainsKey(key))
{
value = pair.Value[key];
return true;
}
}
}
else if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key))
{
value = _dict[ns][key];
return true;
}
value = default(T);
return false;
}
public T this[string ns, string key]
{
get
{
if (ns == "")
{
foreach (var pair in _dict)
if (pair.Value.ContainsKey(key))
return pair.Value[key];
}
else if (_dict.ContainsKey(ns) && _dict[ns].ContainsKey(key))
return _dict[ns][key];
throw new KeyNotFoundException();
}
set
{
if (!_dict.ContainsKey(ns))
_dict[ns] = new Dictionary<string, T>();
_dict[ns][key] = value;
}
}
public T this[string name]
{
get
{
var tuple = Split(name);
return this[tuple.Item1, tuple.Item2];
}
set
{
var tuple = Split(name);
this[tuple.Item1, tuple.Item2] = value;
}
}
public ICollection<string> Keys
{
get { return _dict.SelectMany(p => p.Value.Keys).ToArray(); }
}
public ICollection<T> Values
{
get { return _dict.SelectMany(p => p.Value.Values).ToArray(); }
}
#endregion
}
Test
var dict = new NamespaceDictionary<int>();
dict.Add("ns1.var1", 1);
dict.Add("ns2.var1", 2);
dict.Add("var2", 3);
dict.Add("ns2.var2", 4);
dict.Add("ns3", "var1", 5);
dict["ns4.var1"] = 6;
Console.WriteLine(dict["var1"]);
Console.WriteLine(dict["ns2.var1"]);
Console.WriteLine(dict["var2"]);
Console.WriteLine(dict["ns2.var2"]);
Console.WriteLine(dict["ns2", "var2"]);
Console.WriteLine(dict["ns3.var1"]);
Console.WriteLine(dict["ns4", "var1"]);
Output
1
2
3
4
4
5
6
Help
I used a SortedDictionary thinking it would retain the order that the namespaces were added, but it's actually sorting the namespaces alphabetically. Is there an dict class that will retain the order the items were added, but not sort them?
I need to create a dictionary that has 2 values per key, and it must return one of the 2 values with the same probability.
Example:
myDicry
{
key = "A", value1=15, value2=56;
}
int firstCall = myDicry["A"]; // = 15
int secondCall = myDicry["A"]; // = 56
It would be possible to write an IDictionary<TKey, TValue> implementation that behaved in this manner, but that would not be a good idea: most people would find a non-deterministic indexer for a collection-class very unintuitive.
Instead, I suggest you make this the responsibility of the value for a key, rather than the Dictionary itself. One option would be to write a custom-type that is capable of picking from a set of possibilities with equal probability. For example:
public class UnbiasedRandomPicker<T>
{
private readonly Random _rand = new Random();
private readonly T[] _possibilities;
public UnbiasedRandomPicker(params T[] possibilities)
{
// argument validation omitted
_possibilities = possibilities;
}
public T GetRandomValue()
{
return _possibilities[_rand.Next(_possibilities.Length)];
}
}
You could then use the dictionary like this:
var dict = new Dictionary<string, UnbiasedRandomPicker<int>>
{
{"A", new UnbiasedRandomPicker<int>(15, 56)},
{"B", new UnbiasedRandomPicker<int>(25, 13)}
};
int randomValueFromA = dict["A"].GetRandomValue();
There's nothing built into the framework to do this, but you'd probably want to implement it by creating a "wrapper" type which had a Dictionary<TKey, Tuple<TValue, TValue>>. You'd then write an indexer to choose appropriately between the two values.
I would actually just implement this in a class that uses a Dictionary<TKey, TValue[]> internally. That way you could even implement the type to have a variable number of values per key.
Like:
class RandomDictionary<TKey, TValue>
{
Dictionary<TKey, TValue[]> m_dict;
Random m_random;
public RandomDictionary()
{
m_dict = new Dictionary<TKey, TValue[]>();
m_random = new Random();
}
public TValue this[TKey key]
{
get
{
TValue[] values = m_dict[key];
return values[m_random.Next(0, values.Length)];
}
}
public void Define(TKey key, params TValue[] values)
{
m_dict[key] = new TValue[values.Length];
Array.Copy(values, m_dict[key], values.Length);
}
public bool TryGetValue(TKey key, out TValue value)
{
TValue[] values;
if (!m_dict.TryGetValue(key, out values))
{
value = default(TValue);
return false;
}
value = values[m_random.Next(0, values.Length)];
return true;
}
}
Use Tuple as dictionary value type.
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
// ...
int secondValue = doubleDictionary["A"].Item2;
You could also write an extension method for the dictionary, so you could create something like this:
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
doubleDictionary.GetRandomValueForKey("A");
Then you can use this with any dictionary.
public static void GetRandomValueForKey(this Dictionary<string, Tuple<int, int>> dict,
string key)
{
... Code to return the value
}
^^ that was written off the top of my head, so please excuse me if this is slightly wrong.
This below code will solve the dictionary part of the problem and make the randomization customizable so that you can apply a level so pseudo-randomness that suits your needs. (or simply hard code it instead of the use of a functor)
public class DoubleDictionary<K, T> : IEnumerable<KeyValuePair<K, T>>
{
private readonly Dictionary<K, Tuple<T, T>> _dictionary = new Dictionary<K, Tuple<T, T>>();
private readonly Func<bool> _getFirst;
public DoubleDictionary(Func<bool> GetFirst) {
_getFirst = GetFirst;
}
public void Add(K Key, Tuple<T, T> Value) {
_dictionary.Add(Key, Value);
}
public T this[K index] {
get {
Tuple<T, T> pair = _dictionary[index];
return GetValue(pair);
}
}
private T GetValue(Tuple<T, T> Pair) {
return _getFirst() ? Pair.Item1 : Pair.Item2;
}
public IEnumerable<K> Keys {
get {
return _dictionary.Keys;
}
}
public IEnumerable<T> Values {
get {
foreach (var pair in _dictionary.Values) {
yield return GetValue(pair);
}
}
}
IEnumerator<KeyValuePair<K, T>> IEnumerable<KeyValuePair<K, T>>.GetEnumerator() {
foreach (var pair in _dictionary) {
yield return new KeyValuePair<K, T>(pair.Key, GetValue(pair.Value));
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable<KeyValuePair<K, T>>)this).GetEnumerator();
}
}