0

I am searching of an elegant way to assign values in function of a number belonging to a specific range.

For example, having the number X, the elegant way would return:

  • 'a' - if X is between 0 and 1000
  • 'b' - if X is between 1000 and 1500
  • and so on (but a fixed number of defined intervals)

By elegant I mean something more appealing than

if ((x => interval_1) && (x < interval_2))
    class_of_x = 'a';
else if ((x => interval_2) && (x < interval_3))
    class_of_x = 'b';
...

or

if(Enumerable.Range(interval_1, interval_2).Contains(x))
    class_of_x = 'a';
else if(Enumerable.Range(interval_2 + 1, interval_3).Contains(x))
    class_of_x = 'b';
...

I hate seeing so many IFs. Also, the interval values can be stored in a collection (maybe this would help me eliminate the ISs?), not necessary as interval_1, interval_2 and so on.

Somewhat inspired by this question How to elegantly check if a number is within a range? which came out while looking for a solution for the problem described above.

Community
  • 1
  • 1
Coral Doe
  • 1,925
  • 3
  • 19
  • 36

5 Answers5

1

If my comment is correct then your first if statement has a lot of unnecessary checks, if its not less than interval 2 then it must be greater than or equal to, therefore:

if((x => i1) && (x < i2))
else if(x < i3)
else if(x < i4)...

When a "true" argument is found then the rest of the if statement is irrelevant, as long as your conditions are in order this should suit your needs

Sayse
  • 42,633
  • 14
  • 77
  • 146
  • Seems I have overlooked this for sure. :D Less code, but still a lot of IFs. – Coral Doe Aug 14 '13 at 15:17
  • Other than this there isn't really a way to avoid lots of if statements, you could always do some combination of math.round and a switch statement I guess but thats not really achieving much – Sayse Aug 14 '13 at 15:21
1

You can create extention method:

public static class IntExtensions
{
    // min inclusive, max exclusive
    public static bool IsBetween(this int source, int min, int max)
    {
        return source >= min && source < max
    }
}

and then

// Item1 = min, Item2 = max, Item3 = character class
IList<Tuple<int, int, char>> ranges = new List<Tuple<int, int, char>>();
// init your ranges here
int num = 1;
// assuming that there certainly is a range which fits num,
// otherwise use "OrDefault"
// it may be good to create wrapper for Tuple, 
// or create separate class for your data
char characterClass = ranges.
                        First(i => num.IsBetween(i.Item1, i.Item2)).Item3;
Zbigniew
  • 27,184
  • 6
  • 59
  • 66
1

Firstly, define a little class to hold the inclusive maximum value, and the corresponding value to use for that band:

sealed class Band
{
    public int  InclusiveMax;
    public char Value;
}

Then declare an array of Band which specifies the value to use for each band and loop to find the corresponding band value for any input:

public char GetSetting(int input)
{
    var bands = new[]
    {
        new Band {InclusiveMax = 1000, Value = 'a'},
        new Band {InclusiveMax = 1500, Value = 'b'},
        new Band {InclusiveMax = 3000, Value = 'c'}
    };

    char maxSetting = 'd';

    foreach (var band in bands)
        if (input <= band.InclusiveMax)
            return band.Value;

    return maxSetting;
}

Note: In real code, you would wrap all this into a class which initialises the bands array only once, and not every single time it's called (as it is in the code above).

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
1

Create an Interval class and use LINQ:

public class Interval
{
    public string TheValue { get; set; }
    public int Start { get; set; }
    public int End { get; set; }

    public bool InRange(int x)
    {
        return x >= this.Start && x <= this.End;
    }
}

public void MyMethod()
{
    var intervals = new List<Interval>();

    // Add them here...

    var x = 3213;
    var correctOne = intervals.FirstOrDefault(i => i.InRange(x));

    Console.WriteLine(correctOne.TheValue);
}
0

Here you could also use the static System.Linq.Enumerable's Range() method that implements

IEnumerable<T>

with the Contains() method (again from System.Linq.Enumerable), to do something like:

var num = 254;
if(Enumerable.Range(100,300).Contains(num)) { ...your logic here; }

This looks more elegant in my eyes at least.

C. Sederqvist
  • 2,830
  • 19
  • 27