What is the standard way in C# to check if a number is within a range of numbers?
Typically, I would do some variation of this with int i:
return (i >= start && i <= end);
Is there no syntax for something like this:
// does not work
return (start <= i <= end);
The most close to what you expect is
return start <= i && i <= end;
There are no mathematical notations in C#. Operators are functions that return a result. Usually operators are either unary or binary only (i.e. you cannot pass 3 arguments).
One trick you can do is to introduce an extension method:
public static class IntExtensions
{
public static bool WithinRange(this int value, int low, int high)
=> value >= low && value <= high;
}
So the usage would be:
return i.WithinRange(start, end);
This is more verbose, but more obscure at the same time; does it mean to include lower bound? does it mean to include higher bound?
The suggestion is to stick to the syntax that any software developer knows.
Related
I'm trying to run a sort as below but am running into an issue with the Start properties being of type Long in the Lambda expression. When they were of type int this was working correctly but I need this to work over larger values. I've tried casting the a.Start - b.Start to int but this seems to provide an incorrect sort result.
Is there a different method by which I should be sorting or should I change datatypes?
ranges.Sort((a, b) => a.Start - b.Start);
private readonly List<Range> ranges = new List<Range>();
public class Range
{
public Range(long startEnd) : this(startEnd, startEnd)
{
}
public Range(long start, long end)
{
if (end >= start)
{
Start = start;
End = end;
}
else
{
Start = end;
End = start;
}
}
public long Start { get; private set; }
public long End { get; private set; }
public void Update(long newStart, long newEnd)
{
Start = newStart;
End = newEnd;
}
public static implicit operator Range(long i)
{
return new Range(i);
}
}
Function you pass to Sort should:
return anything negative if a < b (can be always -1 for example)
zero if a == b
anything positive if a > b (can be always 1 for example)
Your current function satisfies this criteria (but not safe to use because of potential overflow), but returns long. There are many other functions that satisfy this criteria though. One is already existing comparer for longs:
ranges.Sort((a, b) => a.Start.CompareTo(b.Start));
You can do the same yourself if you'd like (though no reason to):
ranges.Sort((a, b) => a.Start > b.Start ? 1 : a.Start < b.Start ? -1 : 0);
The delegate you pass to the Sort method is a Comparison<T> which must always return an int, whatever the type T it is comparing.
The int returned from this delegate should be:
A signed integer that indicates the relative values of x and y, as
shown in the following table.
Value Meaning
Less than 0 x is less than y.
0 x equals y.
Greater than 0 x is greater than y.
Therefore the fact that it worked when your Start was an int is actually purely coincidental.
You can fix your case by having your delegate return
a.Start.CompareTo(b.Start)
A comparison is supposed to return an int so you need to convert your long to an int somehow. You can either Convert.ToInt32 or, if that might be out of range, simply return -1 for any negative value and 1 for any positive value.
Another, probably better alternative, would be to use the CompareTo method of one of the values for both int and long, which would be functionally equivalent to the second option.
Casting a.Start - b.Start to int seems to work here, however by doing that you expose yourself to overflow errors (what if a.Start is 0 and b.Start is long.MaxValue, for example?). Since Sort only checks if your lambda is returning a positive value, a negative value or zero, you can do just this:
ranges.Sort((a, b) => a.Start > b.Start ? 1 : a.Start < b.Start ? -1 : 0);
Alternatively, LINQ's OrderBy works just fine (and is not limited to Lists), but be aware that it returns a new object rather than modifying the original one, which may or may not be ok for you:
ranges = ranges.OrderBy(r => r.Start).ToList()
In order to highlight multiple search text elements in a single string, I have a routine computing the ranges to be highlighted within the string itself.
For example, if I search his+is string in string "this is my misk test" I get higlighted ranges [1,3], [2,3], [5,6], and [12,13].
So my desired result here would be [1,3], [5,6], and [12,13].
Is there a general way to extract non-overlapping ranges from the above list? Or event better, is there a string-specific way to get those?
Sort the ranges by start-index. (Your procedure most likely already does this)
Select the first range
Skip all ranges that start before the currently selected range ends (keep checking the next until you find a range that starts after the currently selected range ends)
Select the new range
Goto 3
If you want to do it text based, it depends on the complexity of your possible search patterns (regexes?). If you specify this, I'd be happy to try to help you out.
What do you understand by efficient? Fast? Least memory usage? Mantainable code?
There are tons of ways you could solve this, some of them can entail seemingly a lot of code but maybe thats not bad. For example, consider the following approach:
public struct Interval<T> where T: IComparable<T>
{
public T LowerBound { get; }
public T UpperBound { get; }
public Interval(T lowerBound, T upperBound)
{
Debug.Assert(upperBound.CompareTo(lowerBound) > 0);
LowerBound = lowerBound;
UpperBound = upperBound;
}
public static bool AreOverlapping(Interval<T> first, Interval<T> second) =>
first.UpperBound.CompareTo(second.LowerBound) > 0 &&
second.UpperBound.CompareTo(first.LowerBound) > 0;
public static Interval<T> Union(Interval<T> first, Interval<T> second)
{
Debug.Assert(AreOverlapping(first, second));
return new Interval<T>(Min(first.LowerBound, second.LowerBound),
Max(first.UpperBound, second.UpperBound));
}
public override string ToString() => $"[{LowerBound}, {UpperBound}]";
private static T Min(T t1, T t2)
{
if (t1.CompareTo(t2) <= 0)
return t1;
return t2;
}
private static T Max(T t1, T t2)
{
if (t1.CompareTo(t2) >= 0)
return t1;
return t2;
}
}
And now, our method to extract non-overlapping intervals would be:
public static IEnumerable<Interval<T>> GetOverlappingIntervals<T>(this IEnumerable<Interval<T>> intervals)
where T : IComparable<T>
{
var stack = new Stack<Interval<T>>();
foreach (var interval in intervals.OrderBy(i => i.LowerBound))
{
if (stack.Count == 0)
{
stack.Push(interval);
}
else
{
var previous = stack.Peek();
if (Interval<T>.AreOverlapping(interval, previous))
{
stack.Pop();
stack.Push(Interval<T>.Union(interval, previous));
}
else
{
stack.Push(interval);
}
}
}
return stack;
}
Note that this solution will not perform the union of adjacent intervals, not sure if this is what you want.
Is this solution mantainable? Yes, the code is pretty much self explanatory. Is it the most efficient? Well, probably not, but who cares if its "efficient" enough and it meets your performance goals. If it doesn't, then do start optimizing it.
I'm trying to make a method such as this
public static bool GetInteger(string stringToConvert, out int intOutValue, int minLimit, int maxLimit)
I want it to check if the value is within the min and max range that I specify with the in-values. The parsing is just
int.TryParse(stringToConvert, out intOutValue)
but how do I now check if the value of "intOutValue" is within range? It keeps telling me that it is a bool-value...
Any help on how to do this would be greatly appriciated! (I'm pretty new to programming, and especially in c#)
If you're trying to do comparisons based on the result of the call to TryParse then therein lies your problem; that returns a boolean to indicate success or not (hence the Try). So you need to compare the inOutValue as that's what has been populated.
public static bool GetInteger(string input, out int result, int min, int max) {
return int.TryParse(input, out result) && (result >= min && result <= max);
}
There is no need for an out param here, and I'd even say the method naming is bad, unless you actually want the value to be accessible after the fact.
It looks like you want to check if it is also in the given range, as well as a valid int. In which case you could do:
public static bool GetInteger(string stringToConvert, out int intOutValue, int minLimit, int maxLimit)
{
bool parsed = int.TryParse(stringToConvert, out intOutValue);
return parsed && intOutValue >= minLimit && intOutValue <= maxLimit;
}
I have a method like this:
Prefix GetPrefix(decimal value)
{
if(value > 11000000000000000000)
return Prefix.CosmicBig;
if(value > 1000000000000000)
return Prefix.ReallyBig;
if(value > 3000000000000)
return Prefix.Big;
if(value > 50000000)
return Prefix.Okay;
if(value > 750000)
return Prefix.MostlyNormal;
if(value > 750000)
return Prefix.SoSo;
if(value > 750)
return Prefix.Small;
return Prefix.MiserablySmall;
}
The exact values are not important. What matters is that they are sometimes changed (the prefixes are used for drawing and some text areas change sizes in development). I'm looking for a way of writing these literals in a way that's easily readably by a human changing it, without having to count all the zeroes. A separator would be nice. I thought about writing 11 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000, but that's only barely more manageable. Using Math.Pow() does it a little better, but I'm not comfortable with using such calculations to define constants.
Instead of 11000000000000000000 you can use 11e18. Use m to indicate that it is a decimal, so 11e18m.
You can introduce extension methods for int:
750.Thousand();
5.Million();
100.Billion();
The implementation of these methods is simple:
public static int Thousand(this int value)
{
return value * 1000;
}
public static int Million(this int value)
{
return value.Thousand() * 1000;
}
// etc.
Make sure to return the appropriate data type for methods for bigger numbers:
public static long Billion(this int value)
{
return value.Million() * 1000;
}
Unfortunatelly, you will have to write those methods for every integral or floating point type you want to support.
Having a full set of such extension methods would allow you to express your large numbers in relativly natural ways, even when it's not just all zeros at the end:
100.Billion() + 30.Thousand() + 300 // == 100,000,030,300
If you want to get fancy, you could even think about nesting them:
100.Billion(30.Thousand(300))
But I think that would lose some expressiveness, because people would wonder what the parameter means.
Still, implementation would look like this:
public static long Billion(this int value, long add)
{
return value.Million() * 1000 + add;
}
Using these extension methods has one little downside: Your numbers are no longer compile-time constants. They are calculated at runtime. In the vast majority of cases, this shouldn't be a problem.
A language feature introduced on C# 7.0 is the introduction of _ as a digit separator when inside number literals, so instead of 50000000 you can write 50_000_000.
https://devblogs.microsoft.com/dotnet/new-features-in-c-7-0/#literal-improvements
For very large numbers, or if working with numbers in scientific notation, the solution given by Sjoerd might be a better option.
I am quite new to C# and I was wondering if there is a Class or a data structure or the best way to handle the following requirement...
I need to handle a COUPLE of int that represent a range of data (eg. 1 - 10 or 5-245) and I need a method to verify if an Int value is contained in the range...
I believe that in C# there is a class built in the framework to handle my requirement...
what I need to do is to verify if an INT (eg. 5) is contained in the range of values Eg (1-10) ...
in the case that I should discover that there is not a class to handle it, I was thinking to go with a Struct that contain the 2 numbers and make my own Contain method to test if 5 is contained in the range 1-10)
in the case that I should discover that there is not a class to handle
it, I was thinking to go with a Struct that contain the 2 numbers and
make my own Contain method to test if 5 is contained in the range
1-10)
That's actually a great idea as there's no built-in class for your scenario in the BCL.
You're looking for a range type; the .Net framework does not include one.
You should make an immutable (!) Int32Range struct, as you suggested.
You may want to implement IEnumerable<int> to allow users to easily loop through the numbers in the range.
You need to decide whether each bound should be inclusive or exclusive.
[Start, End) is probably the most obvious choice.
Whatever you choose, you should document it clearly in the XML comments.
Nothing exists that meets your requirements exactly.
Assuming I understood you correctly, the class is pretty simple to write.
class Range
{
public int Low {get; set;}
public int High {get; set;}
public bool InRange(int val) { return val >= Low && val <= High; }
}
A Tuple<int,int> would get you part of the way but you'd have to add an extension method to get the extra behavior. The downside is that the lower- and upper-bounds are implicitly Item1 and Item2 which could be confusing.
// written off-the-cuff, may not compile
public static class TupleExtension
{
public static bool InRange(Tuple<int, int> this, int queryFor)
{
return this.Item1 >= queryFor && this.Item2 <= queryFor;
}
}
You could create an extension if you want to avoid making a new type:
public static class Extensions
{
public static bool IsInRange(this int value, int min, int max)
{
return value >= min && value <= max;
}
}
Then you could do something like:
if(!value.IsInRange(5, 545))
throw new Exception("Value is out of range.");
i think you can do that with an array.
some nice examples and explanation can be found here:
http://www.dotnetperls.com/int-array
Nothing built in AFAIK, but (depending on the size of the range) an Enumerable.Range would work (but be less than optimal, as you're really storing every value in the range, not just the endpoints). It does allow you to use the LINQ methods (including Enumerable.Contains), though - which may come in handy.
const int START = 5;
const int END = 245;
var r = Enumerable.Range(START, (END - START)); // 2nd param is # of integers
return r.Contains(100);
Personally, I'd probably go ahead and write the class, since it's fairly simple (and you can always expose an IEnumerable<int> iterator via Enumerable.Range if you want to do LINQ over it)