Good day for all ;)
Can anyone help me to find algorithms or already resolved solutions for comparing strings like SQL do it.
For instance
In SQL I can compare strings for
= or <=, >, <
e.t.c.
In C# as known we can't do it.
I want to compare something like
"aa" > "b" "ab" < "aa" "abc" >= "bca" and so on..
Also, maybe someone knows by what logic SQL does it?
Strings implement IComparable, so you can use CompareTo.
void Main()
{
if ("a".CompareTo("b") < 0)
{
Console.WriteLine("A is less than B");
}
if ("a".CompareTo("b") <= 0)
{
Console.WriteLine("A is less than or equal to B");
}
if ("a".CompareTo("a") == 0)
{
Console.WriteLine("A equals A");
}
if ("c".CompareTo("b") > 0)
{
Console.WriteLine("C is greater than B");
}
if ("c".CompareTo("b") >= 0)
{
Console.WriteLine("C is greater than or equal to B");
}
}
However, if you want case-insensitive comparison then you will need to use the overload of string.Compare that allows you to ignore case. The logic is the same though.
Well, "aa" < "ab" equals to
bool result = String.Compare("aa", "ab") < 0;
and so on:
// "abc" >= "bca"
bool result = String.Compare("abc", "bca") >= 0;
the general pattern for "left" <=> "right" is
String.Compare("left", "right") <=> 0
since String.Compare(left, right) returns
negative value (say, -123) when left < right
zero when left == right
postivie value (e.g. 789) when 'left > right'
Related
Looking at the following if statement:
var veryLongVariableName = 7;
if (veryLongVariableName > 5 && veryLongVariableName < 18 && veryLongVariableName != 13)
{
//do something...
}
Is there way to write this in a simpler way, so variable name would be not get repeated 3 times inside of if expression? I am looking for a solution that would also work for other value types/reference types.
If you're using C#9, you can use and:
var veryLongVariableName = 7;
if (veryLongVariableName is > 5 and < 18 and not 13)
{
//do something...
}
Because you are checking against constant values, you can create a logical pattern, which uses is followed by and, or and not.
This also uses relational patterns (with the <, >, <= and >= operators); another C#9 pattern matching enhancement.
I am learning my first ever programming language - which is C#.
I am making my first project in my apprenticeship which is teaching me C#. It is to produce a basic calculator.
The basic calculator takes a string input and provides a result. For example, input: "5 + 5". The answer will be 10 in a decimal format.
However, part of my validation is make the even indexes of the string array only be numbers, whilst the odd indexes of the string array can only be operators of "+", "-", "*", "/". How would I do this?
I have tried to do it here but I am struggling:
for (int index = 0; index <= calculatorInput.Length; index++)
{
if (index % 2 == 0)
{
if (Decimal.TryParse(calculatorInput[index]))
{
throw new CalculatorException("Even indexes must contain a number");
}
//check for number
}
else if (//code here)
{
throw new CalculatorException("Odd indexes must contain an operator");
//check for operator
}
}
Sorry if this question is too simple, but I would greatly appreciate the help!
My apologies for the late response. The comment from Rufus L (https://stackoverflow.com/users/2052655/rufus-l) helped to provide the solution I needed at the time.
decimal temp; if (decimal.TryParse(calculatorInput[index].ToString(), out temp)){} The TryParse method takes a string and an out parameter, which you are missing. But there are better ways to do what you want. – Rufus L Nov 1 '19 at 18:58
All answers and comments were very helpful in my development however. The calculator has been finished now though there is always room for improvement.
You can focus on operators for validation. They must always be somewhere inside the input string. Minus operator is an exception here if your calculator accepts negative numbers. But if the calculator is basic and does not support negative numbers, So the code below should be enough for operator validation:
string inputString = "10 + 10";
int index = inputString.IndexOf('+');
if ((index > -1) && ((index == 0) || (index ==inputString.Length-1)))
throw new CalculatorException("YOUR ERROR MESSAGE");
index = inputString.IndexOf('*');
if ((index > -1) && ((index == 0) || (index ==inputString.Length-1)))
throw new CalculatorException("YOUR ERROR MESSAGE");
index = inputString.IndexOf('/');
if ((index > -1) && ((index == 0) || (index ==inputString.Length-1)))
throw new CalculatorException("YOUR ERROR MESSAGE");
index = inputString.IndexOf('-');
if ((index > -1) && ((index == 0) || (index ==inputString.Length-1)))
throw new CalculatorException("YOUR ERROR MESSAGE");
///Calculation code
To increase readability I did not create a nested if-else statement.
After this code block, you can place your calculation code. I think it is enough for a new learner.
I do some tests with Visual Studio Code Metrics. As I can calculate the Cyclomatic Complexity, each if, while, for - operators increase the complexity with 1. I have the next simple method:
static bool ContainsNegative(int a, int b, int c, int d)
{
if (a < 0 || b < 0 || c < 0 || d < 0) return false;
return true;
}
But for it, the Cyclomatic Complexity is 5, instead of 2 (1 for the method + 1 for the if).
My question is - this is because the Code Metrics calculate each condition in if operator as a different if? I.e. my method is equivalent to:
static bool ContainsNegative(int a, int b, int c, int d)
{
if (a < 0) return false;
if (b < 0) return false;
if (c < 0) return false;
if (d < 0) return false;
return true;
}
Here is a screen with results:
Also, is there a list with all rules described in details?
Thank you!
Cyclomatic Complexity measures the number of paths through a function. As you suggest that means that a 1 is added for each control flow statement plus 1 for each logical NOT, AND and OR in each condition.
What the value of 5 is telling you is that you will need 5 unit tests in order to get 100% code coverage of your function.
I create calculator which have buttons with numbers and operators for basic operation (+, -,...) and just want to filter buttons with numbers to detect when is clicked number (between 0-9). Also i put new eventhadler which convert sender to button.
I wondering what will be nice and easy way to filter the buttons with numbers (using linq)
What did i try so far is
if(btn.Text == btn.Text.Contains(x => x >= '0' && x <= '9'))
MessageBox.Show("number " + btn.Text + " is pressed!");
How to make upper code workable?
Here you go, for your immediate needs:
if(btn.Text.All(char.IsDigit))
{
//Do your stuff
}
If all you want to know is that is it a number or not do this. No LINQ is required
LINQ Way to check the numbers are between 0 and 9
if(yourstring.ToCharArray().Where(c=> c < '0' || c > '9').Any())
return false;
else
return true;
To check that it contains a valid number
double num;
if (double.TryParse(btn.Text, out num))
{
// It's a number!
}
or to check less than 10 without linq
static bool IsLessThanTen(string str)
{
foreach (char c in str)
{
if (c < '0' || c > '9')
return false;
}
return true;
}
if you need to check at least one number in the button text, then use below
return btn.Text.Any(char.IsDigit)
If you writing calculator, you better check NCalc - Mathematical Expressions Evaluator for .NET and this CodeProject tutorial
This should work
bool hasNumeric = yourString.IndexOfAny("0123456789".ToCharArray()) > -1;
I have a list of constant numbers. I need to find the closest number to x in the list of the numbers. Any ideas on how to implement this algorithm?
Well, you cannot do this faster than O(N) because you have to check all numbers to be sure you have the closest one. That said, why not use a simple variation on finding the minimum, looking for the one with the minimum absolute difference with x?
If you can say the list is ordered from the beginning (and it allows random-access, like an array), then a better approach is to use a binary search. When you end the search at index i (without finding x), just pick the best out of that element and its neighbors.
I suppose that the array is unordered. In ordered it can be faster
I think that the simpliest and the fastest method is using linear algorithm for finding minimum or maximum but instead of comparing values you will compare absolute value of difference between this and needle.
In the C++ ( I can't C# but it will be similar ) can code look like this:
// array of numbers is haystack
// length is length of array
// needle is number which you are looking for ( or compare with )
int closest = haystack[0];
for ( int i = 0; i < length; ++i ) {
if ( abs( haystack[ i ] - needle ) < abs( closest - needle ) ) closest = haystack[i];
}
return closest;
In general people on this site won't do your homework for you. Since you didn't post code I won't post code either. However, here's one possible approach.
Loop through the list, subtracting the number in the list from x. Take the absolute value of this difference and compare it to the best previous result you've gotten and, if the current difference is less than the best previous result, save the current number from the list. At the end of the loop you'll have your answer.
private int? FindClosest(IEnumerable<int> numbers, int x)
{
return
(from number in numbers
let difference = Math.Abs(number - x)
orderby difference, Math.Abs(number), number descending
select (int?) number)
.FirstOrDefault();
}
Null means there was no closest number. If there are two numbers with the same difference, it will choose the one closest to zero. If two numbers are the same distance from zero, the positive number will be chosen.
Edit in response to Eric's comment:
Here is a version which has the same semantics, but uses the Min operator. It requires an implementation of IComparable<> so we can use Min while preserving the number that goes with each distance. I also made it an extension method for ease-of-use:
public static int? FindClosestTo(this IEnumerable<int> numbers, int targetNumber)
{
var minimumDistance = numbers
.Select(number => new NumberDistance(targetNumber, number))
.Min();
return minimumDistance == null ? (int?) null : minimumDistance.Number;
}
private class NumberDistance : IComparable<NumberDistance>
{
internal NumberDistance(int targetNumber, int number)
{
this.Number = number;
this.Distance = Math.Abs(targetNumber - number);
}
internal int Number { get; private set; }
internal int Distance { get; private set; }
public int CompareTo(NumberDistance other)
{
var comparison = this.Distance.CompareTo(other.Distance);
if(comparison == 0)
{
// When they have the same distance, pick the number closest to zero
comparison = Math.Abs(this.Number).CompareTo(Math.Abs(other.Number));
if(comparison == 0)
{
// When they are the same distance from zero, pick the positive number
comparison = this.Number.CompareTo(other.Number);
}
}
return comparison;
}
}
It can be done using SortedList:
Blog post on finding closest number
If the complexity you're looking for counts only the searching the complexity is O(log(n)). The list building will cost O(n*log(n))
If you're going to insert item to the list much more times than you're going to query it for the closest number then the best choice is to use List and use naive algorithm to query it for the closest number. Each search will cost O(n) but time to insert will be reduced to O(n).
General complexity: If the collection has n numbers and searched q times -
List: O(n+q*n)
Sorted List: O(n*log(n)+q*log(n))
Meaning, from some q the sorted list will provide better complexity.
Being lazy I have not check this but shouldn't this work
private int FindClosest(IEnumerable<int> numbers, int x)
{
return
numbers.Aggregate((r,n) => Math.Abs(r-x) > Math.Abs(n-x) ? n
: Math.Abs(r-x) < Math.Abs(n-x) ? r
: r < x ? n : r);
}
Haskell:
import Data.List (minimumBy)
import Data.Ord (comparing)
findClosest :: (Num a, Ord a) => a -> [a] -> Maybe a
findClosest _ [] = Nothing
findClosest n xs = Just $ minimumBy (comparing $ abs . (+ n)) xs
Performance wise custom code will be more use full.
List<int> results;
int targetNumber = 0;
int nearestValue=0;
if (results.Any(ab => ab == targetNumber ))
{
nearestValue= results.FirstOrDefault<int>(i => i == targetNumber );
}
else
{
int greaterThanTarget = 0;
int lessThanTarget = 0;
if (results.Any(ab => ab > targetNumber ))
{
greaterThanTarget = results.Where<int>(i => i > targetNumber ).Min();
}
if (results.Any(ab => ab < targetNumber ))
{
lessThanTarget = results.Where<int>(i => i < targetNumber ).Max();
}
if (lessThanTarget == 0 )
{
nearestValue= greaterThanTarget;
}
else if (greaterThanTarget == 0)
{
nearestValue= lessThanTarget;
}
else if (targetNumber - lessThanTarget < greaterThanTarget - targetNumber )
{
nearestValue= lessThanTarget;
}
else
{
nearestValue= greaterThanTarget;
}
}