2009-07-16 57 views
18

我正在寻找一种确定数字是否落入指定范围内的流畅方式。我现在的代码看起来像这样:确定一个数字是否落入指定的一组范围内

int x = 500; // Could be any number 

if ((x > 4199 && x < 6800) || 
    (x > 6999 && x < 8200) || 
    (x > 9999 && x < 10100) || 
    (x > 10999 && x < 11100) || 
    (x > 11999 && x < 12100)) 
{ 
    // More awesome code 
} 

有没有更好的方法来做到这一点?

+2

更好的是什么意思?这似乎很合理 – 2009-07-16 13:22:35

+3

@迈克尔:我相信史蒂夫正在寻求一种更有说服力的方法。 – 2009-07-16 13:29:14

+1

我认为你提供的例子是最好的(看起来和可以理解的)说实话! – ThePower 2009-07-16 13:30:14

回答

36

扩展方法?

bool Between(this int value, int left, int right) 
{ 
    return value > left && value < right; 
} 

if(x.Between(4199, 6800) || x.Between(6999, 8200) || ...) 

你也可以做这种可怕的黑客:

bool Between(this int value, params int[] values) 
{ 
    // Should be even number of items 
    Debug.Assert(values.Length % 2 == 0); 

    for(int i = 0; i < values.Length; i += 2) 
     if(!value.Between(values[i], values[i + 1]) 
      return false; 

    return true; 
} 

if(x.Between(4199, 6800, 6999, 8200, ...) 

可怕的黑客,改进:

class Range 
{ 
    int Left { get; set; } 
    int Right { get; set; } 

    // Constructors, etc. 
} 

Range R(int left, int right) 
{ 
    return new Range(left, right) 
} 

bool Between(this int value, params Range[] ranges) 
{ 
    for(int i = 0; i < ranges.Length; ++i) 
     if(value > ranges[i].Left && value < ranges[i].Right) 
      return true; 

    return false; 
} 

if(x.Between(R(4199, 6800), R(6999, 8200), ...)) 

或者更好,但(这不允许重复下限):

bool Between(this int value, Dictionary<int, int> ranges) 
{ 
    // Basically iterate over Key-Value pairs and check if value falls within that range 
} 

if(x.Between({ { 4199, 6800 }, { 6999, 8200 }, ... } 
+4

我会*绝对*使范围不可变。可变性吸这样的事情... – 2009-07-16 13:30:43

+0

哇! _Formatting_在**评论**中! @Jon是的,你是完全正确的。 – 2009-07-16 13:31:33

14

定义一个范围类型,然后cr请求一组范围和一个扩展方法来查看一个值是否位于任何范围内。然后,而不是硬编码值,你可以创建范围,也许个别范围的集合,给他们有用的名称解释为什么你他们感兴趣:

static readonly Range InvalidUser = new Range(100, 200); 
static readonly Range MilkTooHot = new Range (300, 400); 

static readonly IEnumerable<Range> Errors = 
    new List<Range> { InvalidUser, MilkTooHot }; 

... 

// Normal LINQ (where Range defines a Contains method) 
if (Errors.Any(range => range.Contains(statusCode)) 
// or (extension method on int) 
if (statusCode.InAny(Errors)) 
// or (extension methods on IEnumerable<Range>) 
if (Errors.Any(statusCode)) 

您可能感兴趣的MiscUtil的一部分的通用Range类型。它允许以简单的方式迭代,以及:

foreach (DateTime date in 19.June(1976).To(25.December(2005)).Step(1.Days())) 
{ 
    // etc 
} 

(显然,这也是使用某些日期时间/时间跨度相关的扩展方法,但你的想法。)

0

如果你需要遍历在一些点值对,我建议你捕获最大较低值和最低值上,你做的到的变量,并做到:

if (x>max_lower && x <min_upper) 
{ 
    // More awesome code 

} 
+0

如果这不是不可能的话? – 2009-07-16 13:24:27

+0

@ArsenMkrt,说,如果这不是不可能的话,_不是不可能的=可能的?我不确定你在问什么 – 2009-07-16 13:28:39

0

试着这么做:

struct Range 
{ 
    public readonly int LowerBound; 
    public readonly int UpperBound; 

    public Range(int lower, int upper) 
    { LowerBound = lower; UpperBound = upper; } 

    public bool IsBetween(int value) 
    { return value >= LowerBound && value <= UpperBound; } 
} 

public void YourMethod(int someValue) 
{ 
    List<Range> ranges = {new Range(4199,6800),new Range(6999,8200), 
         new Range(9999,10100),new Range(10999,11100), 
         new Range(11999,12100)}; 

    if(ranges.Any(x => x.IsBetween(someValue)) 
    { 
     // your awesome code... 
    } 
} 
1
class Range { 

    public Range(int x, int y) { 
     X = x; 
     Y = y; 
    } 

    public int X { get; set; } 
    public int Y { get; set; } 
} 

var ranges = new List<Range>(); 
ranges.Add(new Range(4199,6800)); 
ranges.Add(new Range(6999,8200)); 
ranges.Add(new Range(9999,10100)); 
ranges.Add(new Range(10999,11100)); 
ranges.Add(new Range(11999,12100)); 

bool inRange = ranges.Count(r => x >= r.X && x <= r.Y) > 0; 
//or -- Based on Jons recommendation 
bool inRange = ranges.Any(r => x >= r.X && x <= r.Y); 
+1

通常使用Any()比Count(...)> 0更好,因为一旦找到匹配它就会停下来。 – 2009-07-16 13:30:02

+0

感谢您的建议,我会将其添加到帖子中。 – Bob 2009-07-16 13:32:07

7

我个人更喜欢@Anton建议的扩展方法 - 但如果你不能这样做,并且会坚持使用你当前的代码,我想你可以通过颠倒第一组在每个如下行条件...

int x = 500; // Could be any number 
if ((4199 < x && x < 6800) || 
    (6999 < x && x < 8200) || 
    (9999 < x && x < 10100) || 
    (10999 < x && x < 11100) || 
    (11999 < x && x < 12100)) 
{ 
    // More awesome code 
} 
+0

这使得它更具可读性。它在Code Complete中被指出,并且从那以后我一直在使用这种风格。 – Carra 2012-08-08 07:09:26

3

LINQ方法:

添加引用:

using System.Linq; 

     /// <summary> 
     /// Test to see if value is in specified range. 
     /// </summary> 
     /// <param name="aStart">int</param> 
     /// <param name="aEnd">int</param> 
     /// <param name="aValueToTest">int</param> 
     /// <returns>bool</returns> 
     public static bool CheckValueInRange(int aStart, int aEnd, int aValueToTest) 
     { 
      // check value in range... 
      bool ValueInRange = Enumerable.Range(aStart, aEnd).Contains(aValueToTest); 
      // return value... 
      return ValueInRange; 
     } 
+2

CheckValueInRange仅在范围的下限处起作用。由于Enumerable.Range的第二个参数是要添加到序列中的值的数量(而不是范围的结尾),因此高于上限的值仍会按范围报告。示例:CheckValueInRange(4199,6800,6801)将返回True,尽管6801超出了期望的上限,因为Enumerable.Range(4199,6800)返回的范围从4199到10998之间的数字。 – 2012-07-09 21:38:20

+0

此方法对性能非常不利,因为数组将被分配长度范围,并且LINQ将尝试迭代它以找到您的测试值。 – 2016-12-05 21:15:48

-1

在帕斯卡(德尔福)你有下面的语句:

if x in [40..80] then 
begin 
end 

因此,如果x的值落在这个范围内,你执行你的命令。我一直在寻找与此相当的C#,但无法找到像这样简单而“优雅”的东西。

如果in()then语句接受字符串,字节等

+3

这是一个C#问题。 – 2012-10-10 20:14:49

+0

没有真正的相关性。 – Mana 2013-09-19 10:44:11

相关问题