When using a SortedDictionary in Linq and iterating over the KeyValuePair it provides, can I be assured that a complex linq query will execute it in ascending order? Here’s a brief, although a bit confusing example:
Random r = new Random(); //build 100 dictionaries and put them into a sorted dictionary //with 'priority' as the key and it is a number 0-99. SortedDictionary<int, Dictionary<int, double>> sortedDict = new SortedDictionary<int, Dictionary<int, double>>(); for (int i = 0; i < 100; i++) { Dictionary<int, double> dict = new Dictionary<int, double>(); //create the dictionary and a random 10 k/v pairs for (int j = 0; j < 10; j++) { dict[r.Next(0, 100)] = r.NextDouble() * i * 10; } sortedDict[i] = dict; } IEnumerable<int> keys = Enumerable.Range(0, 100); //the goal is to find the FIRST existence of the 'key' inside one //of the inner dictionaries going through the SortedDictionary IN ORDER //this appears to work: var qry = from key in keys from priority in sortedDict where priority.Value.ContainsKey(key) let value = priority.Value[key] group value by key into keyGroup let firstValue = keyGroup.First() select new { Key = keyGroup.Key, Value = firstValue }; // the result is as expected, a list of the numbers at most 0-99 and their // value found in the dictionary with the lowest 'priority'
The question(s):
- It appears to work, but can I rely on this behavior?
- Is this efficient, or does the group by throw it off?
- Does adding ‘sortedDict.Reverse()’ work properly too? (it appears to)
- How would PLinq handle this – and would it still be consistent?
If this isn’t guaranteed, I know how I can pull the ‘priority’ into the grouping and order by it after the fact. But I’d rather not…
It would be slightly more efficient without the ‘let’ clause. Just do:
However, you’re still scanning through the dictionary quite a lot with this. Don’t you basically want a reverse map from key to priorities containing that key? That could be constructed much more efficiently. As you say, the example is pretty confusing. If you could tell us what you’re trying to achieve in your real code, we may be able to come up with something better. (If it’s exactly this situation, I can certainly work on that – I’d rather not do so and then find out that reality is very different though!)
Calling Reverse() will indeed work – but it will buffer all the data. If you want it in reverse order, I suggest you give the SortedDictionary an appropriate IComparer to start with.
Parallel LINQ is ‘interesting’ when it comes to order. It may be different right now, but I had fun a while ago when I was plotting the Mandelbrot set using it…