Rounding a value to only a list of certain values in C#

Here's a method using LINQ:

var list = new[] { 12, 15, 23, 94, 35, 48 };
var input = 17;

var diffList = from number in list
               select new {
                   number,
                   difference = Math.Abs(number - input)
               };
var result = (from diffItem in diffList
              orderby diffItem.difference
              select diffItem).First().number;

EDIT: Renamed some of the variables so the code is less confusing...

EDIT:

The list variable is an implicitly declare array of int. The first LINQ statement diffList defines an anonymous type that has your original number from the list (number) as well as the difference between it and your current value (input).

The second LINQ statement result orders that anonymous type collection by the difference, which is your "rounding" requirement. It takes the first item in that list as it will have the smallest difference, and then selects only the original .number from the anonymous type.


Assuming the array is sorted, you could perform a binary search in the array, narrowing it down to which two numbers the given number lies between.

Then once you have these two numbers, you simply round to the nearest of the two.

static int RoundToArray(int value, int[] array) {
    int min = 0;
    if (array[min] >= value) return array[min];

    int max = array.Length - 1;
    if (array[max] <= value) return array[max];

    while (max - min > 1) {
        int mid = (max + min) / 2;

        if (array[mid] == value) {
            return array[mid];
        } else if (array[mid] < value) {
            min = mid;
        } else {
            max = mid;
        }
    }

    if (array[max] - value <= value - array[min]) {
        return array[max];
    } else {
        return array[min];
    }

}

Using linq:

int value = 17;
var values =  new float[] { 12, 15, 23, 94, 35, 48 };
if(value < values.First()) return value.First();
if(value > values.Last()) return value.Last();

float below = values.Where(v => v <= value).Max();
float above = values.Where(v => v >= value).Min();

if(value - below < above - value)
  return below;
else
  return above;

As long as then number of possible values is quite small this should work. If you have thousands of possible values another solution should be used, which takes advantage of values being sorted (if it really is sorted).

Tags:

C#

.Net

Math