Best implementation for Key Value Pair Data Structure? - c#

So I've been poking around with C# a bit lately, and all the Generic Collections have me a little confused. Say I wanted to represent a data structure where the head of a tree was a key value pair, and then there is one optional list of key value pairs below that (but no more levels than these). Would this be suitable?
public class TokenTree
{
public TokenTree()
{
/* I must admit to not fully understanding this,
* I got it from msdn. As far as I can tell, IDictionary is an
* interface, and Dictionary is the default implementation of
* that interface, right?
*/
SubPairs = new Dictionary<string, string>();
}
public string Key;
public string Value;
public IDictionary<string, string> SubPairs;
}
It's only really a simple shunt for passing around data.

There is an actual Data Type called KeyValuePair, use like this
KeyValuePair<string, string> myKeyValuePair = new KeyValuePair<string,string>("defaultkey", "defaultvalue");

One possible thing you could do is use the Dictionary object straight out of the box and then just extend it with your own modifications:
public class TokenTree : Dictionary<string, string>
{
public IDictionary<string, string> SubPairs;
}
This gives you the advantage of not having to enforce the rules of IDictionary for your Key (e.g., key uniqueness, etc).
And yup you got the concept of the constructor right :)

I think what you might be after (as a literal implementation of your question), is:
public class TokenTree
{
public TokenTree()
{
tree = new Dictionary<string, IDictionary<string,string>>();
}
IDictionary<string, IDictionary<string, string>> tree;
}
You did actually say a "list" of key-values in your question, so you might want to swap the inner IDictionary with a:
IList<KeyValuePair<string, string>>

There is a KeyValuePair built-in type. As a matter of fact, this is what the IDictionary is giving you access to when you iterate in it.
Also, this structure is hardly a tree, finding a more representative name might be a good exercise.

Just one thing to add to this (although I do think you have already had your question answered by others). In the interests of extensibility (since we all know it will happen at some point) you may want to check out the Composite Pattern This is ideal for working with "Tree-Like Structures"..
Like I said, I know you are only expecting one sub-level, but this could really be useful for you if you later need to extend ^_^

#Jay Mooney: A generic Dictionary class in .NET is actually a hash table, just with fixed types.
The code you've shown shouldn't convince anyone to use Hashtable instead of Dictionary, since both code pieces can be used for both types.
For hashtable:
foreach(object key in h.keys)
{
string keyAsString = key.ToString(); // btw, this is unnecessary
string valAsString = h[key].ToString();
System.Diagnostics.Debug.WriteLine(keyAsString + " " + valAsString);
}
For dictionary:
foreach(string key in d.keys)
{
string valAsString = d[key].ToString();
System.Diagnostics.Debug.WriteLine(key + " " + valAsString);
}
And just the same for the other one with KeyValuePair, just use the non-generic version for Hashtable, and the generic version for Dictionary.
So it's just as easy both ways, but Hashtable uses Object for both key and value, which means you will box all value types, and you don't have type safety, and Dictionary uses generic types and is thus better.

Dictionary Class is exactly what you want, correct.
You can declare the field directly as Dictionary, instead of IDictionary, but that's up to you.

Use something like this:
class Tree < T > : Dictionary < T, IList< Tree < T > > >
{
}
It's ugly, but I think it will give you what you want. Too bad KeyValuePair is sealed.

Related

Make an existing Dictionary case insensitive .Net

I know how to make a new dictionary case insensitive with the code below:
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
But I'm using WebApi which serializes JSON objects into a class we've created.
public class Notification : Common
{
public Notification();
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings { get; set; }
}
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
Thanks
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
No, it is impossible. You need to create a new dictionary.
Currently the dictionary has all of the keys in various different buckets; changing the comparer would mean that a bunch of keys would all suddenly be in the wrong buckets. You'd need to go through each key and re-compute where it needs to go and move it, which is basically the same amount of work as creating a new dictionary would be.
Whenever an item is added to a dictionary, the dictionary will compute its hash code and make note of it. Whenever a dictionary is asked to look up an item, the dictionary will compute the hash code on the item being sought and assume that any item in the dictionary which had returned a different hash code cannot possibly match it, and thus need not be examined.
In order for a dictionary to regard "FOO", "foo", and "Foo" as equal, the hash code function it uses must yield the same value for all of them. If a dictionary was built using a hash function which returns different values for "FOO", "foo", and "Foo", changing to a hash function which yielded the same value for all three strings would require that the dictionary re-evaluate the hash value of every item contained therein. Doing this would require almost as much work as building a new dictionary from scratch, and for that reason .NET does not support any means of changing the hash function associated with a dictionary other than copying all the items from the old dictionary to a new dictionary, abandoning the old one.
Note that one could design a SwitchablyCaseSensitiveComparator whose GetHashCode() method would always return a case-insensitive hash value, but whose Equals method could be switched between case-sensitive and non-case sensitive operation. If one were to implement such a thing, one could add items to a dictionary and then switch between case-sensitive and non-case-sensitive modes. The biggest problem with doing that would be that adding if the dictionary is in case-sensitive mode when two items are added which differ only in case, attempts to retrieve either of those items when the dictionary is in case-insensitive mode might not behave as expected. If populating a dictionary in case-insensitive mode and performing some look-ups in case-sensitive mode should be relatively safe, however.
Try changing your class definition to something like this
public class Notification : Common
{
public Notification()
{
this.substitutionStringsBackingStore =
new Dictionary<string,string>( StringComparer.OrdinalIgnoreCase )
;
}
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings
{
get { return substitutionStringsBackingStore ; }
set { substitutionStringsBackingStore = value ; }
}
private Dictionary<string,string> substitutionStringsBackingStore ;
}
You do have to re-create the dictionary, but this can be done with extensions:
public static class extensions
{
public static Dictionary<string, T> MakeCI<T>(this Dictionary<string, T> dictionary)
{
return dictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
}
}
I've specified string type for the key as this is what we want to be CI, but the value can be any type.
You would use it like so:
myDict = myDict.MakeCI();

The property KeyValuePair<TKey, Tvalue>.Value has no setter

I'm using a Dictionary<int, KeyValuePair<bool, int>> to hold data.
From time to time I need to increment the int in the KeyValuePair, but it won't let me, because it has no setter. Is there a way to increment it?
Code sample:
Dictionary<int, KeyValuePair<bool, int>> mDictionary =
new Dictionary<int, KeyValuePair<bool, int>>();
mDictionary[trapType].Value++;
//Error: The property KeyValuePair<TKey, Tvalue>>.Value has no setter
Is there a way to increment it?
No. KeyValuePair is immutable - it's also a value type, so changing the value of the Value property after creating a copy wouldn't help anyway.
You'd have to write something like this:
var existingValue = mDictionary[trapType];
var newValue = new KeyValuePair<bool, int>(existingValue.Key,
existingValue.Value + 1);
mDictionary[trapType] = newValue;
It's pretty ugly though - do you really need the value to be a KeyValuePair?
mDictionary[trapType] = new KeyValuePair<bool, int>(mDictionary[trapType].Key, mDictionary[trapType].Value+1)
KeyValuePair tends just to be used as an iterator value for dictionaries. You're better off defining your own type if you want it to be mutable.
another solution is to create a new dictionary and pass the new values and keys to it:
foreach (var d in existingDic)
newDic.Add(d.Key, d.Value + 1);
Conceptually, KeyValuePair<TKey,TValue> is just a pair of variables, Key and Value. Had Microsoft implemented it with exposed public fields Key and Value, the semantics of it would have been perfect; when used as a ForEach control variable it would have been immutable, but one could have updated the Key or Value field of an ordinary variable or array element without having to update the other.
Unfortunately, Microsoft seems to have been unwilling to have framework types expose any public fields, even for types like KeyValuePair<TKey,TValue> or Drawing.Rectangle whose semantics dictate that (1) the type must be a struct; (2) its entire state is visible in a fixed set of properties (there may be other computed properties beyond those which define an object's state), and (3) those properties may be assigned any combination of values suitable for their types. Consequently, Microsoft only considered the possibilities of exposing the members comprising the types' state as read-only properties, or as read-write properties. Using read-write properties would mean that code like:
for each (var item in myDictionary)
item.Value += 1;
or
...assuming MyList is a List<Drawing.Rectangle>
MyList[3].Width += 9;
would be interpreted by the existing C# compiler as either
for each (var item in myDictionary)
{ var temp = item; temp .Value += 1; }
or
...assuming MyList is a List<Drawing.Rectangle>
{ temp = MyList[3]; temp.Width += 9; }
both of yield horrible behavior which is almost certainly not what the programmer intended. The implementers of .net decided that the value of having the members of KeyValuePair<TKey,TValue> be individually mutable did not justify the danger posed by the former, but the usefulness of modifying individual members of Rectangle was sufficient to justify the danger posed by second. Note that neither example would have had to pose any danger had the types used exposed fields rather than properties, since writing to a field of a temporary struct has never been permissible, even when calling property setters was.
As previously mentioned, the KeyValuePair is immutable. I thought it was worth adding here a mutable implementation:
public class MutableKeyValuePair<KeyType, ValueType>
{
public KeyType Key { get; set; }
public ValueType Value { get; set; }
public MutableKeyValuePair() { }
public MutableKeyValuePair(KeyType key, ValueType val)
{
Key = key;
Value = val;
}
}
You will need to construct a new key value pair.
mDictionary[trapType] = new KeyValuePair<bool,int>(mDictionary[trapType].Key,mDictionary[trapType].Value +1);
However if you are on .NET 4, I'd suggest you use a Tuple instead of a key value pair if what you are trying to do is simply to have an object that holds two other values. Ie if there's no key-value relationship between the two. Then code would then be:
mDictionary[trapType] = Tuple.Create(mDictionary[trapType].Item1,mDictionary[trapType].Item2 +1);

Is there a an easier way to initialize a List<KeyValuePair<T, U>>, like a Dictionary<T, U>?

Actually I need something like List<KeyValuePair<T, U>> but I want to be able to initialize it like dictionary (i.e. without writing new KeyValuePair every time). Like this:
Dictionary<string, string> dic = new Dictionary<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
EDIT: It turns out .NET does have a combination list/dictionary type already: OrderedDictionary. Unfortunately this is a non-generic type, making it rather less attractive in my view. However, it retains the insertion order if you just call Add repeatedly.
It's a little strange as calling Add does not affect entries where a key already exists, whereas using the indexer to add a key/value pair will overwrite a previous association. Basically it doesn't seem like a terribly nice API, and I would personally still avoid it unless your use case exactly matches its behaviour.
No, .NET doesn't have any insertion-order-preserving dictionaries. You could always write your own list-based type with the relevant Add method. This might even be one of the few places I'd consider extending an existing type:
public class KeyValueList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
public void Add(TKey key, TValue value)
{
Add(new KeyValuePair<TKey, TValue>(key, value));
}
}
Then:
var list = new KeyValueList<string, string>
{
{ "key1", "value1"},
{ "key2", "value2"}
};
An alternative is to use composition, but my gut feeling is that this is a reasonable use of inheritance. I can't place why I'm happy in this case but not usually, mind you...
Because you do not have a dictionary you cannot use a dictionary initiailzer. You have a list so you could use a list initializer which will be the closest you could get:
var l = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("key1", "value1"),
new KeyValuePair<string, string>("key2", "value2"),
};
Here's the minimum requirement for you to use dictionary initializer: the class must implement IEnumerable and the class must have a public method Add which takes 2 arguments (where the first argument represents the key and the second argument the value). So you could write a custom class which satisfies those requirements and you will be able to use the syntax you have shown in your question.
The code you have typed works fine - further to Mads Togersen's post about the implementation of collection initialisers, the compiler maps the brace-delimited entries ({"key1", "value1"} above) to an Add method on the collection with the same signature - in this case Dictionary.Add(TKey, TValue).

Converting a KeyValuePair collection in to anonymous type

Is it possible to convert a a IEnumerable<KeyValuePair<string,string>> of KeyValuePair to an anonymous type?
Dictionary<string, string> dict= new Dictionary<string, string>();
dict.add("first", "hello");
dict.add("second", "world");
var anonType = new{dict.Keys[0] = dict[0], dict.Keys[1] = dict[1]};
Console.WriteLine(anonType.first);
Console.WriteLine(anonType.second);
********************output*****************
hello
world
The reason i would like to do this is because I am retrieving an object from a webservice that represents an object that does not exist in the wsdl. The returned object only contains a KeyValuePair collection that contains the custom fields and their values. These custom fields can be named anything, so i cant really map an xml deserialization method to the final object i will be using (whose properties must be bound to a grid).
*Just because I used Dictionary<string,string> does not mean it is absolutely a dictionary, i just used it for illustration. Really its an IEnumerable<KeyValuePair<string,string>>
Ive been trying to thing of a way to do this, but am drawing a blank. This is c# .NET 4.0.
You could use the ExpandoObject, it is based on a dictionary.
I think there are a lot of ways to achieve this, but actually converting it in the same Dictionary seems a bit odd to do.
One way to accomplish this, by not actually converting everyting is the following:
public class MyDictionary<T,K> : Dictionary<string,string> // T and K is your own type
{
public override bool TryGetValue(T key, out K value)
{
string theValue = null;
// magic conversion of T to a string here
base.TryGetValue(theConvertedOfjectOfTypeT, out theValue);
// Do some magic conversion here to make it a K, instead of a string here
return theConvertedObjectOfTypeK;
}
}
ExpandoObject is the best option, which I believe is a wrapper around some XML. You could also use an XElement:
var result = new XElement("root");
result.Add(new XElement("first", "hello"));
result.Add(new XElement("second", "world"));
Console.WriteLine(result.Element("first").Value);
Console.WriteLine(result.Element("second").Value);
foreach (var element in result.Elements())
Console.WriteLine(element.Name + ": " + element.Value);
I haven't used ExpandoObject, so I'd try that first because I understand it does exactly what you want and is also something new and interesting to learn.

Change cardinality of item in C# dictionary

I've got a dictionary, something like
Dictionary<Foo,String> fooDict
I step through everything in the dictionary, e.g.
foreach (Foo foo in fooDict.Keys)
MessageBox.show(fooDict[foo]);
It does that in the order the foos were added to the dictionary, so the first item added is the first foo returned.
How can I change the cardinality so that, for example, the third foo added will be the second foo returned? In other words, I want to change its "index."
If you read the documentation on MSDN you'll see this:
"The order in which the items are returned is undefined."
You can't gaurantee the order, because a Dictionary is not a list or an array. It's meant to look up a value by the key, and any ability to iterate values is just a convenience but the order is not behavior you should depend on.
You may be interested in the OrderedDicationary class that comes in System.Collections.Specialized namespace.
If you look at the comments at the very bottom, someone from MSFT has posted this interesting note:
This type is actually misnamed; it is not an 'ordered' dictionary as such, but rather an 'indexed' dictionary. Although, today there is no equivalent generic version of this type, if we add one in the future it is likely that we will name such as type 'IndexedDictionary'.
I think it would be trivial to derive from this class and make a generic version of OrderedDictionary.
I am not fully educated in the domain to properly answer the question, but I have a feeling that the dictionary sorts the values according to the key, in order to perform quick key search. This would suggest that the dictionary is sorted by key values according to key comparison. However, looking at object methods, I assume they are using hash codes to compare different objects considering there is no requirement on the type used for keys. This is only a guess. Someone more knowledgey should fill in with more detail.
Why are you interested in manipulating the "index" of a dictionary when its purpose is to index with arbitrary types?
I don't know if anyone will find this useful, but here's what I ended up figuring out. It seems to work (by which I mean it doesn't throw any exceptions), but I'm still a ways away from being able to test that it works as I hope it does. I have done a similar thing before, though.
public void sortSections()
{
//OMG THIS IS UGLY!!!
KeyValuePair<ListViewItem, TextSection>[] sortable = textSecs.ToArray();
IOrderedEnumerable<KeyValuePair<ListViewItem, TextSection>> sorted = sortable.OrderBy(kvp => kvp.Value.cardinality);
foreach (KeyValuePair<ListViewItem, TextSection> kvp in sorted)
{
TextSection sec = kvp.Value;
ListViewItem key = kvp.Key;
textSecs.Remove(key);
textSecs.Add(key, sec);
}
}
The short answer is that there shouldn't be a way since a Dictionary "Represents a collection of keys and values." which does not imply any sort of ordering. Any hack you might find is outside the definition of the class and may be liable to change.
You should probably first ask yourself if a Dictionary is really called for in this situation, or if you can get away with using a List of KeyValuePairs.
Otherwise, something like this might be useful:
public class IndexableDictionary<T1, T2> : Dictionary<T1, T2>
{
private SortedDictionary<int, T1> _sortedKeys;
public IndexableDictionary()
{
_sortedKeys = new SortedDictionary<int, T1>();
}
public new void Add(T1 key, T2 value)
{
_sortedKeys.Add(_sortedKeys.Count + 1, key);
base.Add(key, value);
}
private IEnumerable<KeyValuePair<T1, T2>> Enumerable()
{
foreach (T1 key in _sortedKeys.Values)
{
yield return new KeyValuePair<T1, T2>(key, this[key]);
}
}
public new IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
{
return Enumerable().GetEnumerator();
}
public KeyValuePair<T1, T2> this[int index]
{
get
{
return new KeyValuePair<T1, T2> (_sortedKeys[index], base[_sortedKeys[index]]);
}
set
{
_sortedKeys[index] = value.Key;
base[value.Key] = value.Value;
}
}
}
With client code looking something like this:
static void Main(string[] args)
{
IndexableDictionary<string, string> fooDict = new IndexableDictionary<string, string>();
fooDict.Add("One", "One");
fooDict.Add("Two", "Two");
fooDict.Add("Three", "Three");
// Print One, Two, Three
foreach (KeyValuePair<string, string> kvp in fooDict)
Console.WriteLine(kvp.Value);
KeyValuePair<string, string> temp = fooDict[1];
fooDict[1] = fooDict[2];
fooDict[2] = temp;
// Print Two, One, Three
foreach (KeyValuePair<string, string> kvp in fooDict)
Console.WriteLine(kvp.Value);
Console.ReadLine();
}
UPDATE: For some reason it won't let me comment on my own answer.
Anyways, IndexableDictionary is different from OrderedDictionary in that
"The elements of an OrderedDictionary are not sorted in any way." So foreach's would not pay attention to the numerical indices
It is strongly typed, so you don't have to mess around with casting things out of DictionaryEntry structs

Categories