0

I have a collection of values:

  • [0-20] = 1
  • [21-30] = 2
  • [31-40] = 3 etc.

I expect input from users in the for of [44] for example. What would be the most eloquent way to determine in which item the value falls?

I can write a switch statement to match a case > < or an if...statement but neither of these in my opinion is eloquent enough.

Update

I'm looking for a neat and tidy way of finding the range in which my user's input fall, using something like LAMDBA for example:

List<int>().Find(x => x.WithinRange(range))

Or something like that.

JadedEric
  • 1,943
  • 2
  • 26
  • 49

7 Answers7

4

Something like this as an extension:

public static int WithinRange(this int value)
{
    if (value < 0) return 0;
    if (value < 21) return 1;
    return (value - 1) / 10;
}

without if statements

public static int WithinRange(this int value)
{
    return (value < 0) ? 0 
        : (value < 21) ? 1 
        : (value - 1) / 10;
}

usage:

collection.Find(x => x.WithinRange(range)) 
hunter
  • 62,308
  • 19
  • 113
  • 113
4

If your ranges are consecutive, as in your example (i.e. there are no gaps), you can store their endpoints in an array, like this:

var endpoints = new[] {20, 30, 40, 60, 90};

Note that the endpoints are sorted. You can now use a binary search method to find the insertion point of 44 in this array, which is 3, will be returned (binary search will return bitwise complement of 3; you'd need to apply ~ to get the actual value).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

There you go:

int GetRange(int value) 
{ 
    return (value > 30) ? 3 :
           (value > 20) ? 2 :
           (value > 0)  ? 1 :
           0;
}

No ifs!

weston
  • 54,145
  • 21
  • 145
  • 203
2

Just loop over the ranges and see if the value falls within the range...

var ranges = new[]
{
    Tuple.Create(0, 20),
    Tuple.Create(21, 30),
    Tuple.Create(31, 40),
    Tuple.Create(41, 50),
    // ...
};
var number = 44;
for (int i = 0; i < ranges.Length; i++)
{
    var range = ranges[i];
    if (number >= range.Item1 && number <= range.Item2)
    {
        var theIndex = i + 1;
        // do something with theIndex
    }
}
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
1

You could just manipulate the inputs:

int input = //Whatever the input is
int index = (input-1)/10;

Assuming integer input, and that your array is indexed as indicated.

NominSim
  • 8,447
  • 3
  • 28
  • 38
0

UPDATE: I know this is an overkill but it might give you some ideas. As I undestand, you already know how to solve this problem, but you are just looking for a "prettier" solution:

public class Range
{
    public int Left { get; set; }   
    public int Right { get; set; }
    public string Title { get; set; }

    public Range(int left, int right, string title) { Left = left; Right = right; Title = title; }

    public bool Contains(int x) { return Left <= x && x <= Right; }
}

void Main()
{
    var x = 15;

    var ranges = new[] {
        new Range(0, 10, "A"),
        new Range(11, 20, "B")
    };

    var foo = ranges.Where(r => r.Contains(x)).Single();

    Console.Write(foo.Title);
}

My previous suggestion: For statement is ok but I prefer LINQ :)

var x = 15;

var ranges = new[] { Tuple.Create(0, 10), Tuple.Create(11, 20) };
var range = ranges.Where(r => r.Item1 <= x && r.Item2 >= x );

Console.Write(range.Item1);
Console.Write(range.Item2);
lalibi
  • 3,057
  • 3
  • 33
  • 41
  • Tuples are 4.0 specific, should have mentioned I'm on a 3.5 project. But thanks for all the feedback guys, really appreciate the expertise on this forum. – JadedEric Feb 02 '12 at 14:40
0

Less efficient .NET 3.5 alternative variation of @Jeff Mercado's answer:

var ranges = new[]
{
    Enumerable.Range(0, 20),
    Enumerable.Range(21, 30),
    Enumerable.Range(31, 40),
    Enumerable.Range(41, 50),
    // ...
};
var number = 44;
for (int i = 0; i < ranges.Length; i++)
{
    var range = ranges[i];
    if (range.Contains(number))
    {
        var theIndex = i + 1;
        // do something with theIndex
    }
}
Roy Goode
  • 2,940
  • 20
  • 22