2012-03-01 59 views
3

我試圖想出做某種類型的開關式的選擇上雙的最好的辦法,找出它是在什麼範圍的事情是這樣的:開關式的C#構造帶雙範圍的情況下

double a = 1.1; 
switch(a) 
{ 
case: (0.0, 1.6) 
return 1; 
case: (1.6, 2.337) 
return 2; 
case: (2.337, 3.2974) 
return 3; 
default: 
    return -1; 
} 

很明顯,在這個例子中,範圍中的一個值必須是非包含的,但是你得到了我的漂移。有任何想法嗎?

編輯時,範圍不一定是整數。

編輯2: 我實際上是在處理弧度,找出其中的12個範圍的一點是我落得這樣做的:

double pi = Math.PI; 
double[] zones = new double[] { 
     0, pi/6, pi/3, pi/2, 
     2*pi/3, 5*pi/6, pi, 7*pi/6, 
     4*pi/3, 3*pi/2, 5*pi/3, 11*pi/6 
    }; 

for (int i = 0; i < 11; i++) 
{ 
    if (radians > zones[i] && radians <= zones[i + 1]) 
    { 
     return i + 1; 
    } 
} 

我開始做一個二進制搜索類型如 - 其他的,但它會變得太混亂。

+0

什麼是有多個假設中的問題? – user1096188 2012-03-01 16:13:30

+0

一個明顯的缺陷是,您打算對浮點數字的數字表示進行等式比較。 – GregC 2012-03-01 16:13:35

+0

對於這個例子,你可以使用'Math.Round()':) – 2012-03-01 16:16:04

回答

7

下非常適合於相鄰的範圍,因爲你只需要編寫一次範圍限制:

double a = 1.1; 

if (a < 0.0) { 
    // Too low 
    return -1; 
} else if (a < 1.6) { 
    // Range [0.0, 1.6) 
    return 1; 
} else if (a < 2.337) { 
    // Range [1.6, 2.337) 
    return 2; 
} else if (a < 3.2974) { 
    // Range [2.337, 3.2974) 
    return 3; 
} else { 
    // Too high 
    return -1; 
} 
+2

+1如果解決方案需要可縮放,則可以將該方法修改爲使用二分搜索,方法是將範圍定義存儲在數組中。那麼你會有O(log n)而不是O(n)。 – phoog 2012-03-01 16:37:22

+0

事實上,我開始編碼我的if-then,但意識到它會變得混亂。 – PhilBrown 2012-03-01 16:50:18

+0

當然,我已經根據問題提出的比例回答了。這種風格應該適用於少數幾個範圍。更重要的是,你會因數據驅動的重構而變得更好(例如,允許@phoog提供的二分搜索) – 2012-03-01 16:53:56

0

你不能這樣做與switch

if(a >= 0 && a < 1) return 1; 
else if(a < 2) return 2; 

或者,你可以寫一個類來保存MINVAL,MAXVAL和outputval,然後就遍歷這些可能性並返回匹配的outputval。

+0

a == 1不正確。 – Deestan 2012-03-01 16:31:04

+0

問題在我的答案後編輯,使其不正確 – eouw0o83hf 2012-03-01 16:32:11

+1

否,我的意思是你的測試範圍重疊。 'a == 1'滿足你的陳述。 – Deestan 2012-03-01 16:35:49

1

只要湊足

double a = 1.1; 
if(d < 0.0) 
    return -1; 
else 
    return (int)Math.Ceiling(a); 
+0

啊,我會編輯我的原文,但範圍不是整數。 – PhilBrown 2012-03-01 16:16:28

+0

好的,這會改變場景。我只是假設他們是。但丹尼爾似乎有一個很好的解決方案。 – Terkel 2012-03-01 16:24:43

3

這可能是在工程,但你可以創建一個Range類具有最小值和最大值和一個回調函數。

然後,只要創建所有的範圍分別與最小值,最大值和回調,並將它們添加到IEnumerable。

使用LINQ找出正確的範圍:

range = Ranges.First(r => r.MinValue <= value and r.MaxValue > value); 

然後,只需調用回調範圍。

0

也許這會做你想做的一個很好的句法結構。請根據用途調整能見度和比較:

public static class Range 
{ 
    public interface ISwitchable 
    { 
     void SetDefault(Action defaultStatement); 
     void Execute(); 
    } 

    public interface ISwitchable<T>: ISwitchable 
     where T: IComparable<T> 
    { 
     T Value { get; set; } 
     void AddCase(ICase<T> caseStatement); 
    } 

    public class Switchable<T> : ISwitchable<T> 
     where T: IComparable<T> 
    { 
     private readonly IList<ICase<T>> _caseStatements = new List<ICase<T>>(); 
     private Action _defaultStatement; 

     #region ISwitchable<T> Members 

     public T Value { get; set; } 

     public void AddCase(ICase<T> caseStatement) 
     { 
      _caseStatements.Add(caseStatement); 
     } 

     public void SetDefault(Action defaultStatement) 
     { 
      _defaultStatement = defaultStatement; 
     } 

     public void Execute() 
     { 
      foreach (var caseStatement in _caseStatements) 
       if ((caseStatement.Min.CompareTo(Value) <= 0) && (caseStatement.Max.CompareTo(Value) > 0)) 
       { 
        caseStatement.Action(); 
        return; 
       } 

      _defaultStatement(); 
     } 

     #endregion 
    } 

    public interface ICase<T> 
     where T: IComparable<T> 
    { 
     T Min { get; set; } 
     T Max { get; set; } 

     Action Action { get; set; } 
    } 

    public sealed class Case<T>: ICase<T> 
     where T: IComparable<T> 
    { 
     #region ICase<T> Members 

     public T Min { get; set; } 

     public T Max { get; set; } 

     public Action Action { get; set; } 

     #endregion 
    } 

    public static ISwitchable<T> Switch<T>(T value) 
     where T: IComparable<T> 
    { 
     return new Switchable<T>(); 
    } 
} 

public static class SwitchableExtensions 
{ 
    public static Range.ISwitchable<T> Case<T>(this Range.ISwitchable<T> switchable, T min, T max, Action action) 
     where T: IComparable<T> 
    { 
     switchable.AddCase(new Range.Case<T>{ Min = min, Max = max, Action = action }); 
     return switchable; 
    } 
    public static void Default(this Range.ISwitchable switchable, Action action) 
    { 
     switchable.SetDefault(action); 
     switchable.Execute(); 
    } 
} 

用法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Range.Switch(10) 
      .Case(0, 3,() => Console.WriteLine("Between 0 and 3")) 
      .Case(3, 7,() => Console.WriteLine("Between 3 and 7")) 
      .Default(() => Console.WriteLine("Something else")); 
    } 
}