12

I have a dictionary structure, with multiple key value pairs inside.

myDict.Add(key1, value1);
myDict.Add(key2, value2);
myDict.Add(key3, value3);

My dictionary is used as a data source for some control. In the control's dropdown I see the items are like this:

key1
key2
key3

The order looks identical to my dictionary. I know Dictionary is not like arrayList - you can get the index or so. I cannot use sortedDictionary. Now I need to add one more key value pair to this dictionary at some point of my program and I hope it has the same effect as I do this:

myDict.Add(newKey, newValue);
myDict.Add(key1, value1);
myDict.Add(key2, value2);
myDict.Add(key3, value3);

If I do this, I know newKey will display in my control as first element.

I have an idea to create a tempDict, put each pair in myDict to tempDict, then clear myDict, then add pairs back like this:

myDict.Add(newKey, newValue);
myDict.Add(key1, value1);
myDict.Add(key2, value2);
myDict.Add(key3, value3);

Is there better way than this?

Thanks!

Joe
  • 80,724
  • 18
  • 127
  • 145
spspli
  • 3,128
  • 11
  • 48
  • 75

5 Answers5

25

Dictionary<K,V> does not have an ordering. Any perceived order maintenance is by chance (and an artifact of a particular implementation including, but not limited to, bucket selection order and count).

These are the approaches (just using the Base Class Libraries BCL) I know about:

  1. Lookup<K,V>
    • .NET4, immutable, can map keys to multiple values (watch for duplicates during building)
  2. OrderedDictionary
    • Old, non-generic, expected Dictionary performance bounds (other two approaches are O(n) for "get(key)/set(key)")
  3. List<KeyValuePair<K,V>>
    • .NET2/3 okay, mutable, more legwork, can map keys to multiple values (watch for duplicates in inserts)

Happy coding.


Creating a hash data-structure that maintains insertion order is actually only a slight modification of a standard hash implementation (Ruby hashes now maintain insertion order); however, this was not done in .NET nor, more importantly, is it part of the Dictionary/IDictionary contract.

ahsteele
  • 26,243
  • 28
  • 134
  • 248
  • What do you mean by "watch inserts" on Lookup? Do you mean that one needs to be careful when inserting values into a Lookup? If so, then that's not true, because Lookup is immutable. – phoog Sep 22 '11 at 22:54
  • @phoog Since it *can* handle a single key to multiple values it is possible to lead to situations not possible with a dictionary. The wording was not ideal. –  Sep 22 '11 at 23:08
5

You cannot do that with the Dictionary class. It is working in your example because of a quirk in the way the data structure is implemented. The data structure actually stores the entries in temporal order in one array and then uses another array to index into the entry array. Enumerations are based on the entry array. That is why it appears to be ordered in your case. But, if you apply a series of removal and insertion operations you will notice this ordering gets perturbed.

Use KeyCollection instead. It provides O(1) retrieval by both key and index and preserves temporal ordering.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
  • 1
    +1 Wish I knew about KeyCollection before (but why is it off in the ComponentModel namespace and why does it rely on being extended? :-/) –  Sep 22 '11 at 21:11
  • +1 [KeyedCollection](http://msdn.microsoft.com/en-us/library/ms132438.aspx) is just what i was looking for! – Ben Feb 22 '13 at 12:53
2

From the MSDN page on Dictionary(TKey, TValue):

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<(Of <(TKey, TValue>)>) structure representing a value and its key. The order in which the items are returned is undefined.

I'm assuming you can't use SortedDictionary because the control depends on your data source being a Dictionary. If the control expects both the Dictionary type and sorted data, the control needs to be modified, because those two criteria contradict each other. You must use a different datatype if you need sorting/ordering functionality. Depending on undefined behavior is asking for trouble.

Jim Dagg
  • 2,044
  • 22
  • 29
1

Don't use a dictionary - there is no guarantee the order of the keys won't change when you add further elements. Instead, define a class Pair for your Key-Value-Pairs (look here What is C# analog of C++ std::pair? for an example) and use a List<Pair> for your datasource. The List has an Insert operation you can use to insert new elements anywhere into your list.

Community
  • 1
  • 1
Doc Brown
  • 19,739
  • 7
  • 52
  • 88
  • but my control need dictionary to feed data source and we don't want to change the control. – spspli Sep 22 '11 at 21:00
  • 1
    @spspli: what the good doctor is saying is you don't get to ignore the basics of `Dictionary`. So either you change your data structure or you live with an unordered collection. – user7116 Sep 22 '11 at 21:01
  • 3
    When you want your control to display elements in a specific, list-like order, and the only allowed datasource is a dictionary - which does not provide a specific order - then your control is misdesigned and you cannot expect to find a solution for your problem. So either you change your control, use a different control or find out more about your control if there is an alternative way of getting the ordering information somewhere from outside into it. – Doc Brown Sep 22 '11 at 21:07
  • Does your control need a Dictionary<,> or an IDictionary<,>? If the latter, then you can implement the IDictionary<,> interface around List or any other insertion-ordered solution that you like. – phoog Sep 22 '11 at 22:58
1

Dictionary Should not be used to sort objects, it should rather be used to look up objects. i would suggest something else if you want to have it sort the objects too.

If you expand the Dictionary, there are no rule that would stop it from mixing up your List.

Delusional Logic
  • 808
  • 10
  • 32