Reputation: 31
How can I write a function that accepts an array of integers and an integer x and returns the index of the integer in the array that is closest to x argument without being larger than x. If all are above x, the function will return negative one. Assuming two or more numbers cannot be the same in array.
Upvotes: 1
Views: 44
Reputation: 45947
assuming that are numbers are unique you could use
public static int GetClosestIndex(int[] arr, int value)
{
var result = arr.Where(x => x < value).OrderByDescending(x => x);
return result.Any() ? Array.IndexOf(arr, result.FirstOrDefault()) : -1;
}
Update: (for Zastai)
here is a better performing approach
public static int GetClosestIndex(int[] arr, int value)
{
int result = -1;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] < value)
{
if (result == -1 || arr[i] > arr[result])
{
result = i;
}
}
}
return result;
}
Upvotes: 2
Reputation: 1265
I'd go with
public static class StackOverflow {
public static int IndexOfValueClosestTo<T>(this IList<T> list, T x) where T : IComparable<T> {
var closestValue = default(T);
var closestIndex = -1;
var idx = -1;
foreach (var v in list) {
++idx;
if (v.CompareTo(x) < 0 && (closestIndex == -1 || closestValue.CompareTo(v) < 0)) {
closestIndex = idx;
closestValue = v;
}
}
return closestIndex;
}
}
It is still very readable, works on arrays, lists, ... and handles integers, doubles, ...
It's also an extension method, so you can use both StackOverflow.IndexOfValueClosestTo(mylist, myvalue)
and mylist.IndexOfValueClosestTo(myvalue)
.
Some basic benchmarks in LINQPad with an array of a million elements also show this to be 30 times faster than the LINQ-based answer (with 100 iterations this takes ~1.05s where the LINQ version takes ~37s).
For the absolute best performance, however, use a version specialized to int arrays:
public static int IndexOfValueClosestTo(this int[] list, int x) {
var closestValue = 0;
var closestIndex = -1;
var idx = -1;
foreach (var v in list) {
++idx;
if (v < x && (closestIndex == -1 || closestValue < v)) {
closestIndex = idx;
closestValue = v;
}
}
return closestIndex;
}
That runs the 100 iterations in ~0.33s, so it's about 3 times as fast as the generic version above. Note that you can define both as overloads, so you still have a working implementation for, say, a list of doubles.
Upvotes: 2