views:

1079

answers:

5

I am currently developing a program that uses C#'s Dictionary container (specifically, SortedDictionary). This container works very well for my purposes except for one specific case because I want random access. Specifically, I am generating a random position using a pseudorandom number generator and I need to be able to access that value in the SortedDictionary. At the point that this happens, I do not have a key value.

I could potentially switch to a List which would solve this problem, but would create problems in the rest of the algorithm where SortedDictionary works quite well. Any suggestions/solutions would be much appreciated.

I am currently developing Visual Studio 2005.

Thank you.

A: 

Will pulling a random key work?

var randValue = myDictionary.Values.ToList()[myRandomInt];

Edit:

Seems the keys collection and values collection are both IEnumerables so you can't use [] operators. This is the best it gets it seems.

Edit:

Without Linq... Perhaps expensive, but you could copyto array and then pull a value at an index

System.Collections.Generic.KeyValuePair<string, int>[] dictCopy = new System.Collections.Generic.KeyValuePair<string, int>[myDictionary.Count];
myDictionary.CopyTo(dictCopy, 0);
var randValue = dictCopy[myRandomInt].Value;
Joel Potter
That would work, but, as far as I can tell, AllKeys is not available to me. Otherwise, this would be perfect.
JasCav
Edited. The collection is called Keys.
Joel Potter
+3  A: 

You can use a SortedList and it has a Values collection which you may access through an integer index.

eulerfx
Given the frequency of how often I need random access for this one part, I may switch to using a List. Thank you for this suggestion.
JasCav
+1  A: 

Linq could do this for you:

int n = GetRandomIndex();
object item = dictionary.ElementAt(n).Value;
Fredrik Mörk
Expensive, isn't it?
arbiter
+1, This is as good as it's going to get for SortedDictionary<T>.
LukeH
He's using VS2005, so LINQ isn't an option.
Colin
@Colin: that restriction was added to the question after my answer. @arbiter: Whether it's expensive or not depends entirely on the amount of data and the frequency of performing the operation.
Fredrik Mörk
+2  A: 
    public TValue GetRandomElement<TKey, TValue>(SortedDictionary<TKey, TValue> dict)
    {
        Random randGen = new Random();
        int randIndex = randGen.Next(dict.Values.Count);
        int i = 0;
        foreach (TValue value in dict.Values)
        {
            if (i++ == randIndex)
                return value;
        }

        // this shouldn't happen unless I have a bug above or you are accessing the dictionary from multiple threads
        return default(TValue);
    }

Blindly enumerating the ValueCollection is not the most efficient thing in the world. But it gets the job done. If this is a frequent operation in your scenario, you should consider a hybrid data structure that has the performance characteristics needed for both dictionary lookup and random access.

Richard Berg
He's using VS2005. No LINQ.
John Saunders
The question didn't say anything about 2005 when I wrote my answer. But ok -- I've edited code to only use C# 2.0 features.
Richard Berg
A: 

You don't provide enough information to come up with a solution. How many elements, how often are you going to do this, do you have memory/speed constraints? BTree, SortedList, inserting special nodes in the SortedDictionary could all be useful

Stephan Eggermont