22

Is there a method or technique that allows you to insert an element into a Dictionary<TKey, TValue> guaranteeing that the item is in the first index of that dictionary's KeyCollection.

For example:

Dictionary<String, String> dic = foo.GetOutput(); 

// `dic` is something like:

// {"foo", "baa"},
// {"a", "b"}

I need something like:

dic.Add("key", "value", 0);
// where `0` is the index that `key` to be inserted.

foreach(KeyValuePair<String, String> key in dic) 
{
     Console.WriteLine("{0} = {1}", key.Key, key.Value);
}

Output:

key = value
foo = baa
a = b
halfer
  • 19,824
  • 17
  • 99
  • 186
Jack
  • 16,276
  • 55
  • 159
  • 284
  • 2
    What is your requirement to do use a Dictionary? The order of items in a Dictionary collection are intended to be flexible (you can re-sort them, etc.), the index is hidden from use. You may want to use a different type of collection that will be more appropriate depending on your needs. – Guy Starbuck Jan 06 '12 at 16:37

9 Answers9

29

By not using a dictionary.

Dictionary<TKey, TValue> is implemented as a hash-table. The position of keys internal to the dictionary depends upon the hash-code, the means by which that hash-code was reduced further to provide an index into its internal structure, and the order of insertion in an entirely implementation-dependant way.

This isn't the only way to implement a dictionary. SortedDictionary<TKey, TValue> uses a tree structure internally and so always keeps keys in an order. In this case we still can't insert something in the beginning, rather we insert something and it gets put in the appropriate place.

If ordering is what you care about most, then you don't want a puredictionary at all. Rather you want either a List<KeyValuePair<TKey, TValue>> or you want a structure that offers both the functionality of a list and of a dictionary, which is provided by OrderedDictionary. This isn't generic, but you can easily create a generic wrapper around it (doesn't give the performance benefits of internally using generics, but does give type-safety in use).

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • So, what is the purpose of method like `OrderBy`? (Linq extension). In which order would enumeration access entries? – Keren Jan 05 '16 at 13:35
  • @Keren The purpose is to receive elements ordered by a particular criteria and something enumerating through it would access the elements in that order. (The source would be accessed in whatever order and the ordering happens when that has completed). I'm not sure how this is relevant. – Jon Hanna Jan 05 '16 at 13:37
  • What i'm trying to say is that dictionary does have some kind of order that doesn't depends on the `Key`. For this reason, I would expect a way to control this order. I understand there isn't. – Keren Jan 05 '16 at 13:45
  • 2
    @Keren, no, dictionary has no such order that depends on the `Key`. For one thing it's possible to use types that aren't comparable as `Key` which would be impossible if dictionaries needed to order them. – Jon Hanna Jan 05 '16 at 13:54
16

I know it is a three years old question. But found a workaround of this problem. It may help someone

Dictionary<String, String> dic = foo.GetOutput();

dic = (new Dictionary<string, string> {{"key","value"}}).Concat(dic).ToDictionary(k => k.Key, v => v.Value);

This will insert the element in the beginning of dictionary :)

MJK
  • 3,434
  • 3
  • 32
  • 55
  • 1
    This is a implementation detail, also if the dictionary resizes it's internal array you are not guaranteed that the first item will stay the first item. – Scott Chamberlain Jun 26 '16 at 17:41
9

Dictionaries are unordered; elements are meant to be retrieved with a key, whose hash points to its value's location.

What you might want is a List <KeyValuePair>, whose elements can be inserted into a specific index.

List<KeyValuePair<string, string>> list = dic.ToList();
list.Insert(0, new KeyValuePair<string, string>("a", "b"));

foreach(KeyValuePair<string, string> pair in list)
    Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
3

This is not possible with Dictionary<TKey, TValue> as it presents it's values in an unordered fashion when enumerated. There is SortedDictionary<TKey, TValue> which provides ordering but it does so by using an IComparer<TKey> against the key value directly. Here you want the key to be a String and have ordering based on an int. That is not possible with either of these types.

I think you'll need to implement a new type with these very specific semantics in them. For example.

class OrderedMap<TKey, TValue> {
  private readonly Dictionary<TKey, TValue> _map = new Dictionary<TKey, TValue>();
  private readonly List<TKey> _list = new List<TKey>();

  public void Add(TKey key, TValue value) {
    if (!_map.ContainsKey(key)) {
      _list.Add(key);
    }
    _map[key] = value;
  }

  public void Add(TKey key, TValue value, int index) {
    if (_map.ContainsKey(key)) {
      _list.Remove(key);
    }
    _map[key] = value;
    _list.Insert(index, key);
  }

  public TValue GetValue(TKey key) {
    return _map[key];
  }

  public IEnumerabe<KeyValuePair<TKey, TValue>> GetItems() {
    foreach (var key in _list) { 
      var value = _map[key];
      yield return new KeyValuePair<TKey, TValue>(key, value);
    }
  }
}

Note this does come with some non-trivial performance differences over a traditional Dictionary<TKey, TValue>. For example Add and Remove are slower.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
2

this is my solution, maybe not the best solution but it works. =)

public static ComboBox FillDropDownList(Dictionary<String, String> dictionary, ComboBox dropDown, String selecione)
{
    var d = new SortedDictionary<String, String>();

    d.Add("0", selecione);

    foreach (KeyValuePair<string, string> pair in dictionary)
    {
        d.Add(pair.Key, pair.Value);
    }

    dropDown.DataSource = new BindingSource(d, null);
    dropDown.DisplayMember = "Value";
    dropDown.ValueMember = "Key";

    dropDown.SelectedIndex = 0;

    return dropDown;
}
Elton da Costa
  • 167
  • 2
  • 2
  • 7
2

Dictionary<TKey, TValue> is inherently unordered (or rather, the ordering is unpredictable and shouldn't be relied upon). If you want some sort of ordering, you need to use a different type. It's hard to recommend any particular type without knowing more about your requirements.

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

The Dictionary<TKey,TValue> class does not hold items in an ordered manner, so there is no "first" item.

There is a SortedDictionary<Tkey,TValue> (.NET 4.0+), which sorts by the key, but again, this is a very vague idea of "first".

Oded
  • 489,969
  • 99
  • 883
  • 1,009
2

The Dictionary<TKey, TValue> can't be ordered.

You can try SortedDictionary<TKey, TValue> instead, but that one is ordered by the Key, not by a separate index.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
1

A Dictionary is an un-ordered collection. You could try OrderedDictionary - http://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary.aspx - which has an Insert() method which is what you're after.

RichardW1001
  • 1,985
  • 13
  • 22