Reputation: 133
I have a Dictionary;
Dictionary<int, float> delta = new Dictionary<int, float>();
which contains:
0, 45,2345
7, 25,3556
18, 23,2334
How can i find the value of the closest, lower key to a number?
Imagine I have the number 16, id like to find the value of key 7. Same for 4, id like the value of key 0.
Preferably i'd also like the fastest way to do this, since i have to run the operation several million times.
I use C#, .NET 4.
Upvotes: 2
Views: 2734
Reputation: 186668
I suggest using sorted list instead of dictionary, e.g.
List<Tuple<int, float>> delta = new List<Tuple<int, float>>() {
new Tuple<int, float>(0, 45.2345F),
new Tuple<int, float>(7, 25.3556F),
new Tuple<int, float>(18, 23.2334F),
};
// Sort the list
delta.Sort((left, right) => left.Item1.CompareTo(right.Item1));
// ... And binary search then
int index = delta.BinarySearch(new Tuple<int, float>(16, 0.0F),
Comparer<Tuple<int, float>>.Create(
(left, right) => left.Item1.CompareTo(right.Item1)));
if (index < 0) // If there's not exact match
index = ~index - 1; // - 1 - ...then return low bound
else // in case of exact match
index -= 1; // -= 1 ... return low bound as well
...
// Test: "(7, 25.3556)"
Console.Write(delta[index].ToString());
Please note, that you can well have index == -1
in case that there're no items lower than the target
Upvotes: 4
Reputation: 15982
You can filters the keys keeping only the lowers, then gets the max key:
Dictionary<int, float> delta = new Dictionary<int, float>();
var key = 16;
var maxKey = delta.Keys.Where(k => k < key).Max();
var value = delta[maxKey];
However, as noted in the comments a better approach is use classes like SortedDictionary<>
or SortedList<>
.
If all add/remove operations runs first, and later only searches are performed a solution can be convert the keys to array (O(N)) and use Array.BinarySearch()
method (O(log N)):
SortedDictionary<int, float> sortedDict = new SortedDictionary<int, float>();
// Add-Remove operations
var keys = sortedDict.Keys.ToArray();
// Search operations
int maxKey = Array.BinarySearch(keys, key);
float value = maxIndex >= 0 ? sortedDict[maxKey] : sortedDict[~maxIndex - 1];
Upvotes: 1
Reputation: 3009
This should give you what you want
List<Store> list = new List<Store> { new Store() { Number = 0, Number2 = 452345F }, new Store() { Number = 7, Number2 = 253556F }
, new Store() { Number = 18, Number2 = 232334F }};
int number = 16;
var closest = list.Aggregate((x, y) => Math.Abs(x.Number - number) < Math.Abs(y.Number - number) ? x : y);
Console.WriteLine(closest.Number2);
class Store
{
public int Number { get; set; }
public float Number2 { get; set; }
}
Upvotes: -3