15

How can I find the index of an element of a dictionary based on the element key? I'm using the following code to go through the dictionary:

foreach (var entry in freq)
{
    var word = entry.Key;
    var wordFreq = entry.Value;
    int termIndex = ??????;
}

Could anyone help please?

leppie
  • 115,091
  • 17
  • 196
  • 297
FSm
  • 2,017
  • 7
  • 29
  • 55
  • 3
    A `Dictionary` is not a collection which has a numeric indexer. You might want to use an [`OrderedDictionary`](http://msdn.microsoft.com/en-us/library/system.collections.specialized.ordereddictionary.aspx) instead. – Tim Schmelter Nov 21 '12 at 09:12
  • A very [closely related question](https://stackoverflow.com/q/4538894/465053). – RBT Jul 31 '17 at 03:29

8 Answers8

10

There is no concept of an index in a Dictionary. You can't rely on any order of items inside the Dictionary. The OrderedDictionary might be an alternative.

var freq = new OrderedDictionary<string, int>();
// ...

foreach (var entry in freq)
{
    var word = entry.Key;
    var wordFreq = entry.Value;
    int termIndex = GetIndex(freq, entry.Key);
}


public int GetIndex(OrderedDictionary<string, object> dictionary, string key) 
{
    for (int index = 0; index < dictionary.Count; index++)
    {
        if (dictionary.Item[index] == dictionary.Item[key]) 
            return index; // We found the item
    }

    return -1;
}
LainIwakura
  • 2,871
  • 2
  • 19
  • 22
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • 1
    This would only work if all the values are unique within the dictionary, which is not necessarily the case. – LayerCake Aug 31 '16 at 07:07
7

This might work and this is probably not the most efficient way of doing this. Also im not sure why you would want something like this.

Int termIndex = Array.IndexOf(myDictionary.Keys.ToArray(), someKey);
dylful
  • 89
  • 1
  • 4
6

There is no way to get index, since data storing in memory in absolutely different ways for array and dictionary.

When you declare array of any type, you know, that data will be placed in memory cells one after the other. So, index is a shift of memory address.

When you put data in a dictionary, you can't predict the address, that will be used for this item, because it will be placed in specific empty position, which will provide balanced graph for fast search by key. So, you can't manipulate with dictionary data using index.

P.S. I believe, that you can resolve your problem using Linq.

Warlock
  • 7,321
  • 10
  • 55
  • 75
4

There is 2 extension methods

Index by key

public static int IndexOf<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) 
    {
        int i = 0;
        foreach(var pair in dictionary)
        {
            if(pair.Key.Equals(key))
            {
                return i;
            }
            i++;
        }
        return -1;
    }

Index by value

public static int IndexOf<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TValue value) 
    {
        int i = 0;
        foreach(var pair in dictionary)
        {
            if(pair.Value.Equals(value))
            {
                return i;
            }
            i++;
        }
        return -1;
    }
Vakun
  • 231
  • 1
  • 8
3

Maybe something like this could work:

public static int GetIndex(Dictionary<string, object> dictionary, string key) 
{
    for (int index = 0; index < dictionary.Count; index++)
    {
        if(dictionary.Skip(index).First().Key == key)
            return index;
    }

    return -1;
}

Based on Dennis Traub solution, but using a Dictionary... (it's orderer by the original addition)

rasputino
  • 691
  • 1
  • 8
  • 24
1

As Dennis states there is no index in dictionary but in your example the position in the foreach loop could be tracked as so:

int index = -1;
foreach (var entry in freq)
            {

                var word = entry.Key;
                var wordFreq = entry.Value;
                int termIndex = ++index;


            }
Richard
  • 21,728
  • 13
  • 62
  • 101
  • This is wrong due to post increment - it will return -1, 0, 1, etc. It should be `++index`. – Sir Crispalot Nov 21 '12 at 09:21
  • Guys, I have a philosophical question how are you going to use this index? – Warlock Nov 21 '12 at 09:31
  • for that matter there is no code further in the loop at all, I must assume this is just part of the loop interior – Richard Nov 21 '12 at 09:36
  • Yes Richard, you are right, but this is not a good practice to use index for dictionary and it will lead to issues in the future work. I believe, that Linq may resolve the problem of Qaesar. But this is a question to the author of this post ;) – Warlock Nov 21 '12 at 09:49
1

It's old but someone might use it - I currently use

public static int OrderedDictIndexOfKey(string key, OrderedDictionary oDict)
{
    int i = 0;
    foreach (DictionaryEntry oDictEntry in oDict)
    {
        if ((string)oDictEntry.Key == key) return i;
        i++;
    }

    return -1;
}

public static object OrderedDictKeyAtIndex(int index, OrderedDictionary oDict)
{
    if (index < oDict.Count && index >= 0)
    {
        return oDict.Cast<DictionaryEntry>().ElementAt(index).Key;
    }
    else
    {
        return null;
    }
}
Raiven66
  • 51
  • 2
0

The dictionary implementation in .NET hashtable has no defined index because it is based on a hash key. I find the answers here to be inefficient and slow because many of these solutions do not preserve the time complexity of the O (1) Dictionary data structure. The ordered dictionary has some performance disadvantages compared to the dictionary.

The only once efficient possible solution is to add an index while building the dictionary. So you should have e.g.

Dictionary<string, Tuple <int, int >>

where in the tuple you would add an index if you add a new key-value pair. This simple solution preserves the time O (1) and in addition you can have a property with an index.

Ondrej Rozinek
  • 563
  • 8
  • 14
  • Python has recently switched to order-preserving dictionary. I guess the performance is different from indexable dictionary, though, as it only provides preserved-order iteration. But it's a brilliant feature especially for testing and also for JSON-like output formats. – Pavel Šimerda Mar 05 '20 at 13:56