smohamed
smohamed

Reputation: 3314

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

I have a list of double values, I want to Round a variable's value to only that list of numbers

Example:

The list contents are: {12,15,23,94,35,48}

The Variable's value is 17, So it will be rounded to 15

If The variable's value is less than the least number, it will be rounded to it, if it's value is larger than the largest number, it will be rounded to it.

The list contents is always changing according to an external factor, So I cannot hardocde the values I Want to round up or down to.

How can do it in C# ?

Upvotes: 10

Views: 2987

Answers (6)

Damian Kuczaj
Damian Kuczaj

Reputation: 1

Simple rounding down in linq

    public decimal? RoundDownToList(decimal input, decimal[] list)
    {
        var result = (from number in list
                      where number <= input
                      orderby number descending
                      select number).FirstOrDefault();

        return result;
    }

Upvotes: 0

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];
    }

}

Upvotes: 6

Yuck
Yuck

Reputation: 50835

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.

Upvotes: 13

Eric
Eric

Reputation: 6425

Do something like this:

double distance = double.PositiveInfinity;
float roundedValue = float.NaN;
foreach (float f in list)
{
    double d = Math.Abs(d - f);
    if (d < distance)
    {
        distance = d;
        roundedValue = f;
    }
}

Upvotes: 1

orangething
orangething

Reputation: 740

You could loop through the array of numbers and set a roundedNum variable equal to each one if a variable delta is less than the current lowest delta. Some things are best described in code.

int roundedNum = myNum;
int delta = myArray[myArray.Length-1] + 1;

for(int i=0; i<myArray.Length; ++i) {
    if(Math.Abs(myNum - myArray[i]) < delta) {
        delta = Math.Abs(myNum - myArray[i]);
        roundedNum = myArray[i];
    }
}

That should do the trick quite nicely.

Upvotes: 1

Anders Abel
Anders Abel

Reputation: 69260

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).

Upvotes: 2

Related Questions