46

I would like to know if some property or method exists that gets the index of a specific value.

I found that dictionaries have the Contains() method which returns true if the value passed in exists, so this method almost implements what I need.

I know that I can loop through all the value pairs and check the condition, but I ask because maybe there's an optimized way of doing this.

alex
  • 6,818
  • 9
  • 52
  • 103
mjsr
  • 7,410
  • 18
  • 57
  • 83

8 Answers8

50

Let's say you have a Dictionary called fooDictionary

fooDictionary.Values.ToList().IndexOf(someValue);

Values.ToList() converts your dictionary values into a List of someValue objects.

IndexOf(someValue) searches your new List looking for the someValue object in question and returns the Index which would match the index of the Key/Value pair in the dictionary.

This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.

This does not however account for the issue that there may be several matching "someValue" objects.

EricM
  • 747
  • 5
  • 7
41

There's no such concept of an "index" within a dictionary - it's fundamentally unordered. Of course when you iterate over it you'll get the items in some order, but that order isn't guaranteed and can change over time (particularly if you add or remove entries).

Obviously you can get the key from a KeyValuePair just by using the Key property, so that will let you use the indexer of the dictionary:

var pair = ...;
var value = dictionary[pair.Key];
Assert.AreEqual(value, pair.Value);

You haven't really said what you're trying to do. If you're trying to find some key which corresponds to a particular value, you could use:

var key = dictionary.Where(pair => pair.Value == desiredValue)
                    .Select(pair => pair.Key)
                    .FirstOrDefault();

key will be null if the entry doesn't exist.

This is assuming that the key type is a reference type... if it's a value type you'll need to do things slightly differently.

Of course, if you really want to look up values by key, you should consider using another dictionary which maps the other way round in addition to your existing dictionary.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks, that is what i was looking for. I think i need to pull up my skills in LINQ. I read somewhere that LINQ is highly optimized, do you know if using that query is better than a foreach loop, check for every value and then return the key? – mjsr Dec 27 '10 at 20:35
  • 3
    @voodoomsr: No, it would basically be doing a foreach loop within LINQ. How else could it do it, really? – Jon Skeet Dec 27 '10 at 21:13
10

Consider using System.Collections.Specialized.OrderedDictionary, though it is not generic, or implement your own (example).

OrderedDictionary does not support IndexOf, but it's easy to implement:

public static class OrderedDictionaryExtensions
{
    public static int IndexOf(this OrderedDictionary dictionary, object value)
    {
        for(int i = 0; i < dictionary.Count; ++i)
        {
            if(dictionary[i] == value) return i;
        }
        return -1;
    }
}
max
  • 33,369
  • 7
  • 73
  • 84
  • +1 For `OrderedDictionary`, since `Dictionary` does not have indices. – Brian Dec 27 '10 at 15:37
  • I make a mistake in the question, i was referring to the key not the index, but what you respond here inspiring me to make other modifications, thanks. – mjsr Dec 27 '10 at 20:38
5
    You can find index by key/values in dictionary
Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("a", "x");
myDictionary.Add("b", "y");
int i = Array.IndexOf(myDictionary.Keys.ToArray(), "a");
int j = Array.IndexOf(myDictionary.Values.ToArray(), "y");
malik masis
  • 487
  • 1
  • 6
  • 15
  • 1
    Thank you for this code snippet, which might provide some limited short-term help. A proper explanation [would greatly improve](//meta.stackexchange.com/q/114762) its long-term value by showing *why* this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – Toby Speight Jul 11 '18 at 15:14
4

You can use LINQ to help you with this.

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "hi");
dict.Add(2, "NotHi");
dict.Add(3, "Bah");

var item = (from d in dict
            where d.Value == "hi"
            select d.Key).FirstOrDefault();

Console.WriteLine(item); //Prints 1
George Stocker
  • 57,289
  • 29
  • 176
  • 237
1

If searching for a value, you will have to loop through all the data. But to minimize code involved, you can use LINQ.

Example:

Given Dictionary defined as following:

Dictionary<Int32, String> dict;

You can use following code :

// Search for all keys with given value
Int32[] keys = dict.Where(kvp => kvp.Value.Equals("SomeValue")).Select(kvp => kvp.Key).ToArray();
        
// Search for first key with given value
Int32 key = dict.First(kvp => kvp.Value.Equals("SomeValue")).Key;
Community
  • 1
  • 1
decyclone
  • 30,394
  • 6
  • 63
  • 80
1

In your comment to max's answer, you say that what you really wanted to get is the key in, and not the index of, the KeyValuePair that contains a certain value. You could edit your question to make it more clear.

It is worth pointing out (EricM has touched upon this in his answer) that a value might appear more than once in the dictionary, in which case one would have to think which key he would like to get: e.g. the first that comes up, the last, all of them?

If you are sure that each key has a unique value, you could have another dictionary, with the values from the first acting as keys and the previous keys acting as values. Otherwise, this second dictionary idea (suggested by Jon Skeet) will not work, as you would again have to think which of all the possible keys to use as value in the new dictionary.

If you were asking about the index, though, EricM's answer would be OK. Then you could get the KeyValuePair in question by using:

yourDictionary.ElementAt(theIndexYouFound);

provided that you do not add/remove things in yourDictionary.

PS: I know it's been almost 7 years now, but what the heck. I thought it best to formulate my answer as addressing the OP, but of course by now one can say it is an answer for just about anyone else but the OP. Fully aware of that, thank you.

zerzevul
  • 417
  • 5
  • 11
-1

no , there is nothing similar IndexOf for Dictionary although you can make use of ContainsKey method to get whether a key belongs to dictionary or not

TalentTuner
  • 17,262
  • 5
  • 38
  • 63