我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
我如何用c#优雅地做到这一点?
例如,一个数字可以是1到100之间。
我知道一个简单的if (x >= 1 && x <= 100)就足够了;但是有很多语法糖和新特性不断添加到c# /。Net这个问题是关于更习惯的(一个可以称之为优雅的)写法。
性能不是问题,但请在非O(1)的解决方案中添加性能说明,因为人们可能会复制粘贴建议。
当前回答
编辑:提供了新的答案。 当我写这个问题的第一个答案时,我刚刚开始使用c#,事后我意识到我的“解决方案”是幼稚和低效的。
我最初的回答是: 我会选择更简单的版本:
' if(Enumerable.Range(1100).Contains(intInQuestion)){…DoStuff;} '
更好的方法
因为我还没有看到任何其他更有效的解决方案(至少根据我的测试),我将再试一次。
新的和更好的方法,也适用于负范围:
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
这可以用于正负范围,并且默认为
1 . . 100(包括)并使用x作为数字来检查,然后是由min和max定义的可选范围。
为好的措施添加例子
示例1:
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
Console.WriteLine(inRange(25));
Console.WriteLine(inRange(1));
Console.WriteLine(inRange(100));
Console.WriteLine(inRange(25, 30, 150));
Console.WriteLine(inRange(-25, -50, 0));
返回:
True
True
True
False
True
示例2: 使用100000个1到150之间的随机整数的列表
// Returns true if x is in range [min..max], else false
bool inRange(int x, int min=1, int max=100) => ((x - max)*(x - min) <= 0);
// Generate 100000 ints between 1 and 150
var intsToCheck = new List<int>();
var randGen = new Random();
for(int i = 0; i < 100000; ++i){
intsToCheck.Add(randGen.Next(150) + 1);
}
var counter = 0;
foreach(int n in intsToCheck) {
if(inRange(n)) ++counter;
}
Console.WriteLine("{0} ints found in range 1..100", counter);
返回:
66660 ints found in range 1..100
Execution Time: 0.016 second(s)
其他回答
我会创建一个Range对象,就像这样:
public class Range<T> where T : IComparable
{
public T InferiorBoundary{get;private set;}
public T SuperiorBoundary{get;private set;}
public Range(T inferiorBoundary, T superiorBoundary)
{
InferiorBoundary = inferiorBoundary;
SuperiorBoundary = superiorBoundary;
}
public bool IsWithinBoundaries(T value){
return InferiorBoundary.CompareTo(value) > 0 && SuperiorBoundary.CompareTo(value) < 0;
}
}
那么你可以这样使用它:
Range<int> myRange = new Range<int>(1,999);
bool isWithinRange = myRange.IsWithinBoundaries(3);
这样你就可以在其他类型中重用它。
像这样的怎么样?
if (theNumber.isBetween(low, high, IntEx.Bounds.INCLUSIVE_INCLUSIVE))
{
}
扩展方法如下(已测试):
public static class IntEx
{
public enum Bounds
{
INCLUSIVE_INCLUSIVE,
INCLUSIVE_EXCLUSIVE,
EXCLUSIVE_INCLUSIVE,
EXCLUSIVE_EXCLUSIVE
}
public static bool isBetween(this int theNumber, int low, int high, Bounds boundDef)
{
bool result;
switch (boundDef)
{
case Bounds.INCLUSIVE_INCLUSIVE:
result = ((low <= theNumber) && (theNumber <= high));
break;
case Bounds.INCLUSIVE_EXCLUSIVE:
result = ((low <= theNumber) && (theNumber < high));
break;
case Bounds.EXCLUSIVE_INCLUSIVE:
result = ((low < theNumber) && (theNumber <= high));
break;
case Bounds.EXCLUSIVE_EXCLUSIVE:
result = ((low < theNumber) && (theNumber < high));
break;
default:
throw new System.ArgumentException("Invalid boundary definition argument");
}
return result;
}
}
Using an && expression to join two comparisons is simply the most elegant way to do this. If you try using fancy extension methods and such, you run into the question of whether to include the upper bound, the lower bound, or both. Once you start adding additional variables or changing the extension names to indicate what is included, your code becomes longer and harder to read (for the vast majority of programmers). Furthermore, tools like Resharper will warn you if your comparison doesn't make sense (number > 100 && number < 1), which they won't do if you use a method ('i.IsBetween(100, 1)').
我要做的唯一另一个评论是,如果你检查输入的意图是抛出异常,你应该考虑使用代码契约:
Contract.Requires(number > 1 && number < 100)
这比if(…)抛出new Exception(…)更优雅,如果有人试图调用您的方法而没有首先确保该数字在边界内,您甚至可以得到编译时警告。
如果您关心@Daap对已接受答案的注释,并且只能传递一次值,则可以尝试以下方法之一
bool TestRangeDistance (int numberToCheck, int bottom, int distance)
{
return (numberToCheck >= bottom && numberToCheck <= bottom+distance);
}
//var t = TestRangeDistance(10, somelist.Count()-5, 10);
or
bool TestRangeMargin (int numberToCheck, int target, int margin)
{
return (numberToCheck >= target-margin && numberToCheck <= target+margin);
}
//var t = TestRangeMargin(10, somelist.Count(), 5);
In C, if time efficiency is crucial and integer overflows will wrap, one could do if ((unsigned)(value-min) <= (max-min)) .... If 'max' and 'min' are independent variables, the extra subtraction for (max-min) will waste time, but if that expression can be precomputed at compile time, or if it can be computed once at run-time to test many numbers against the same range, the above expression may be computed efficiently even in the case where the value is within range (if a large fraction of values will be below the valid range, it may be faster to use if ((value >= min) && (value <= max)) ... because it will exit early if value is less than min).
不过,在使用这样的实现之前,请先对目标机器进行基准测试。在某些处理器上,由两部分组成的表达式可能在所有情况下都更快,因为两个比较可能是独立完成的,而在减法和比较方法中,减法必须在比较执行之前完成。