1

I want a collection that will store key-value pairs of floats to ints (the float is the key). I then want to find the key value pair with the lowest number. So, I essentially want to grab the int value with the lowest associated float key.

Perhaps a collection that keeps them ordered based on the key and allows me to index into it so as to grab the object at index 0 would be appropriate? I am not sure where to start looking for this however.

Dollarslice
  • 8,654
  • 20
  • 52
  • 80

2 Answers2

9

You could try SortedDictionary. If you call .Keys on it, you will get a sorted collection of keys back. You can then use the LINQ .First() function to get the first key in the collection, for example:

var mySortedDictionary = new SortedDictionary<float, int>();

// ...
// Add some values to dictionary
// ...

// Note, you will need the System.Linq namespace for First()
float firstKey = mySortedDictionary.Keys.First();
int firstValue = mySortedDictionary[firstKey];
// If you just need the value:
int firstValue2 = mySortedDictionary.Values.First();

If you needed to get a key other than the first or last one, you can use the LINQ .ToArray() or .ToList() functions to return an indexable array or list, like so:

float[] indexableKeys = mySortedDictionary.Keys.ToArray();
int[] indexableValues = mySortedDictionary.Values.ToArray();

Additionally, the following code will iterate through the collection and give you all of the KeyValuePairs in sorted order:

foreach (var pair in mySortedDictionary)
{
    int key = pair.Key;
    // Do stuff with key...
    object value = pair.Value;
    // Do stuff with value...
}

As an alternative, you could also use SortedList, which is indexable. To use this, you would just need the following code:

var mySortedList = new SortedList<float, int>();
// ...
// Add some values to sortedlist
// ...
int firstValue = mySortedList.Values[0];

Note: I haven't had a chance to benchmark either of these, so I'm not sure which would perform better. Using a sorted collection definitely has more overhead than a regular one. If you only need to know which key is the first one, you may be best off creating a custom class that contains a Dictionary and a private field private float first; that stores which key is the first one. When you add to that class, it adsd teh KeyValuePair to the dictionary and checks to see if the key is smaller than your first variable (or if there are no keys in the dictionary). If so, it sets first to the new key. When you remove a value, you again would remove it from the Dictionary. If the key is equal to your first value, then you'd need to sort the Dictionary.Keys collection and find the new first. This would probably perform the best, but you would have to write the class yourself.

Note: After doing some benchmarks, I found that SortedDictionary is faster for removal, but SortedList is faster for adding and indexing by key. This was done by populating a regular dictionary with 1,000,000 keyValue pairs (keys were shuffled so that they'd be entered in random order). I then:

  • Added each of those pairs to both sorted collections
  • Performed a lookup on each key in both sorted collections
  • Removed each pair by calling Remove(Key) on both sorted collections

SortedList was about twice as fast when adding or indexing, but took about 1000 times the amount of time to remove each element.

Jon Senchyna
  • 7,339
  • 2
  • 23
  • 45
  • My first implementation had a bug in it. You cannot access `SortedDictionary.Keys` with an indexer. If you want to get the first element, you can call the `.First()` LINQ extension method on it. – Jon Senchyna Jun 08 '12 at 14:42
  • But what if duplicates are allowed? (as i've commeted he could use a[`OrderedMultiDictionary`](http://powercollections.codeplex.com/)). – Tim Schmelter Jun 08 '12 at 14:45
  • If you choose to use a fully sorted collection, consider the differences between `SortedDictionary` and `SortedList` (see under "Remarks" in the documentation linked at the very beginning of the above answer). With a `SortedList`, you **can** say `mySortedList.Keys[0]` to get the least key, but clearly there are more important differences between the to sorted collections. – Jeppe Stig Nielsen Jun 08 '12 at 14:51
  • So if I can do that with a SortedList, why shouldn't I use one? – Dollarslice Jun 08 '12 at 15:20
  • @SirYakalot Of course, in either case `mySortedCollection.Values.First()` works and is equvalent to `mySortedCollection.First().Value`, so it's easy to find the value component of the first pair, no matter if you use `SortedDictionary` or `SortedList`. Which of the two to use depends on how you add, insert and remove entries from the collection. Do you need to modify the collection often? – Jeppe Stig Nielsen Jun 08 '12 at 15:42
  • @JeppeStigNielsen yes I regularly have to add to the collection. Thanks for all the help by the way! – Dollarslice Jun 08 '12 at 15:48
  • @SirYakalot If you add a lot to your collection (compare to how often you read), and if the new keys added could have any size (not typically greater than the existing keys), then I think `SortedDictionary` is fastest. But if you rarely change your collection, just populate it once (maybe even in an ordered fashion), then `SortedList<>` will be fastest. – Jeppe Stig Nielsen Jun 08 '12 at 15:56
  • 1
    @SirYakalot , @JeppeStigNielsen I did some benchmark testing of both classes and found that `SortedList` is marginally faster when adding, and then indexing a million records (`SortedList` took 20ms, `SortedDictionary` took 60ms to add them, 40ms to index them). On the flip-side, if you do a lot of deletes, SortedDictionary is vastly superior (`SortedDictionary` took 57ms to delete the records, whereas `SortedList` took a shocking 6901ms). The benchmark code is ~100 lines long, so I won't attach it here. – Jon Senchyna Jun 08 '12 at 16:02
  • thank you this is very helpful! although, where were the deletes being carried out? on index 0? – Dollarslice Jun 09 '12 at 11:20
  • I created a list of unique floats and shuffled it, I then iterated through that and used the values as the keys for adds, indexes, and deletes. That allowed me to use the same random set of indexes for both collections, and ensure that I wasn't inserting or deleting records in an already sorted order. – Jon Senchyna Jun 09 '12 at 15:37
0

Of course you can use any completely sorted data structure. But the "completely sorted" part has of course some overhead involved.

If only the lowest key should be retrieved, then a "priority queue" is usually the best data structure. An appropriate question has been asked here.

Community
  • 1
  • 1
A.H.
  • 57,703
  • 14
  • 82
  • 113