tags:

views:

109

answers:

4

Suppose I have a sorted array of integers int[], and I want to search the closest smaller value to some input number.

for example if the array contains (1) , (23), (57) , (59), (120) and the input is 109, the output should be 59.

I am just trying to see suggestions and compare to the approaches I already have.

+10  A: 

Use Array.BinarySearch. If the input is in the list, it will return the index, and if not then it will return the complement of the index of the first larger value. You just invert the result and subtract one to get the index of the closest smaller value.

int[] arr = { 1, 23, 57, 59, 120 };
int index = Array.BinarySearch(arr, 109);
if (index < 0)
{
    index = ~index - 1;
}
if (index >= 0)
{
    var result = arr[index];
}

Note that if you have an input smaller than the smallest element, you don't have a well-defined answer.

Quartermeister
when will (index >= 0) in the last if not be true? (and no I'm not looking for when index is less than zero :P)
Rune FS
@Rune FS: Try searching for 0. `~index` will be 0 since 1 is the next-highest number, so `~index - 1` will be -1. There is no element smaller than the input, so there is no valid answer.
Quartermeister
@Quartermeister got it
Rune FS
+4  A: 

using Linq:

int[] arr = new[] { 1, 23, 57, 59, 120 };
int target = 109;
int max = arr.Where(n => n < target).Max();

Maybe not the fastest but probably the easiest to implement. Also doesn't rely on the array being sorted, as binary search does.

Note that the call to Max will throw an exception if the Where filter results in no elements, so you might want to check that if it's a possibility.

fearofawhackplanet
oh - snap. great minds :)
jim
possible duplicate :P http://stackoverflow.com/questions/3492840/find-the-largest-value-smaller-than-x-in-a-sorted-array/3492964#3492964
Mustafa A. Jabbar
mustapha - cute :).. btw, as they were so similar, have updated mine to show fear's suggestion re checking fo exceptions
jim
Shouldn't it be n <= target?
adam0101
+2  A: 

I'd go for a linq solution (updated: to add a little more code to stop from being similar to fear's similar solution):

int[] arr1 = { 1, 23, 57, 59, 120 };
int maxResult;
string errorMsg;
try
{
    maxResult = arr1.Where(x => x <= 109).Max();
}
catch(Exception e)
{
    errorMsg = e.Message;
    // do some error stuff here :)
    return null;
}
// party on your maxResult...

cheers jim

jim
+1  A: 

just to extrapolate on the other LINQ solutions this extension method will return -1 if no objects fits the filter and expects that the list is all positive integers

public static int SearchForLimit(this IEnuemerable<int> sequence, Predicate<int> filter)
{
   return (from i in sequence
           let n = filter(i) ? i : -1
           select n).Max()
}

usage would look like this:

int[] arr1 = { 1, 23, 57, 59, 120 };
int limitedBy109 = arr1.SearchForLimit(i => i < 109);
Rune FS