2009-07-16 51 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

相關問題