4

Consider the following code:

var myDict = new Dictionary<string, int>();

myDict.Add("Key1", 1);
myDict.Add("Key2", 2);
myDict.Add("Key4", 4);
myDict.Add("Key5", 5);

foreach (KeyValuePair<string, int> pair in myDict)
{
    Console.Write(pair.Key + @" --> ");
    Console.WriteLine(pair.Value);
}

myDict.Add("Key3", 3);
foreach (KeyValuePair<string, int> pair in myDict)
{
    Console.Write(pair.Key + @" --> ");
    Console.WriteLine(pair.Value);
}

What I want to do is insert "Key3" in between "Key2" and "Key4". I am using this as an example for simplicity's sake. I know I could use a SortedDictionary and I could get this example to work. What I need to be able to do specifically though is, whenever I insert a new element into the dictionary, I ALWAYS want it to insert it after the 2nd element and before the 3rd element. How can I accomplish this?

Icemanind
  • 47,519
  • 50
  • 171
  • 296

6 Answers6

12

You can use an OrderedDictionary for this. OrderedDictionary.Insert allows you to specify the index at which the key will be inserted.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Nice catch Jon. Here I thought I knew all the collection classes in the BCL. Learn something new every day. – Sam Axe Oct 27 '11 at 15:33
  • +1 -- This is exactly what I was looking for. I, too, completely forgot this existed – Icemanind Oct 27 '11 at 15:35
  • It is non-generic, however. You might want to roll your own collection, using a Dictionary and List together. – thecoop Oct 27 '11 at 16:30
  • @thecoop: I 'd prefer aggregating `OrderedDictionary` and just exposing a typed interface over it. – Jon Oct 27 '11 at 16:31
  • @Jon: That does mean that you're boxing things unnecessarily; using a List and Dictionary prevents that. – thecoop Oct 27 '11 at 16:39
  • @thecoop: Indeed, but as a practical matter IMHO you 'd have to profile the code or not concern yourself with that at all. Who's to say if boxing is a greater evil than a homebrew `List` + `Dictionary` implementation performance-wise? In a library method I fully agree that cutting down on boxing is a worthy goal. – Jon Oct 27 '11 at 16:45
  • @thecoop: There is a generic implementation for OrderedDictionary [here at this site](http://www.codeproject.com/KB/recipes/GenericOrderedDictionary.aspx) – Icemanind Oct 27 '11 at 17:01
3

There's no concept of "between" in a Dictionary<,>. It's an unordered mapping. Iterating over it will give unpredictable results which may change between framework versions. If you want to preserve some sort of ordering, you could have a separate List<T> or LinkedList<T> representing the notional key order. You'd have to keep them up to date with respect to each other.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

The Dictionary<TKey,TVal> class. has no concept of sorted keys. You want a SortedDictionary, which will sort your dictionary by the key.

Polynomial
  • 27,674
  • 12
  • 80
  • 107
2

This is not possible with a standard Dictionary<TKey, TValue> type. It is inherently an unordered collection. Any attempt at guaranteeing ordering will not work.

With a SortedDictionaryTKey, TValue> this could work if you make the comparer aware of an elements place in the Dictionary. However this is almost certainly the wrong approach. It really sounds like you want a List<T> here..

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

This is not what a dictionary is for. A dictionary is unsorted, by definition. There is no such thing as the 2nd or 4th element, as they are only accessed by key.

The items are enumerated in the order you add them simply because of the internal implementation of Dictionary used by the particular CLR version you happen to be running (see here for a post on how Dictionary is actually implemented to understand why it does this)

Use a SortedDictionary or SortedList instead, or, if you want to insert into particular indexes, roll your own collection combining a Dictionary (for O(1) key lookup) and a List (to maintain the key order and insert at a particular index). OrderedDictionary might do what you are looking for, but it's a non-generic collection.

thecoop
  • 45,220
  • 19
  • 132
  • 189
1

Dictionaries are meant to have their values accessed via their keys.. not via indices. So you should think about using an array or List instead.

Sam Axe
  • 33,313
  • 9
  • 55
  • 89