I needed to implement a recursive method that checks whether an input is a palindrome or not. I was able to do this in one line and it works, but I'm not sure about how readable this is. I also keep getting a message "Simplify conditional ternary expression" but I'm not sure how
this is my code:
private static bool checkIfPalindrome(string i_InputToCheck, int i_StartIndex, int i_EndIndex)
{
return (i_StartIndex >= i_EndIndex) ? true : checkIfPalindrome(i_InputToCheck, i_StartIndex + 1, i_EndIndex - 1) && (i_InputToCheck[i_StartIndex] == i_InputToCheck[i_EndIndex]);
}
how readable this is
First off, naming convention: Get rid of unnecessary/uninformative parts of identifiers. For example, parameters do not need to start with i_ (presumably to denote “input”?). There’s no information conveyed here, and it adds noise. This has a huge impact on readability.
The logic itself can also be decluttered. The warning you’re getting gives you a hint that the condition can be simplified — this is always the case when your conditionals contain boolean literals.
More than anything, however, readability would benefit from breaking the expression up over multiple lines.
I would also swap the two secondary conditions, so that you first test the current characters, and then recurse further (only if the two currently tested characters are equal!):
private static bool IsPalindrome(string input, int start, int end) {
return (start >= end) ||
input[start] == input[end] &&
IsPalindrome(input, start + 1, end - 1);
}
This code relies on the correct precedence of && over ||. Some peope prefer making this operator precedence explicit by using more parentheses:
private static bool IsPalindrome(string input, int start, int end) {
return (start >= end) ||
(
input[start] == input[end] &&
IsPalindrome(input, start + 1, end - 1)
);
}
return i_StartIndex >= i_EndIndex || checkIfPalindrome(i_InputToCheck, i_StartIndex + 1, i_EndIndex - 1) && i_InputToCheck[i_StartIndex] == i_InputToCheck[i_EndIndex];
The simplification being prompted is because you're testing a boolean expression and then unnecessarily checking and returning it...
if (expression == true) is equivalent to if (expression) and
return expression ? true : false to return expression.
It is certainly not easy on the eye but I assume this is for a school exercise?
Related
I have a rather complex issue that I'am unable to figure out.
I'm getting a set of string every 10 seconds from another process in which the first set has first 5 characters constant, next 3 are variable and can change. And then another set of string in which first 3 are variable and next 3 are constant.
I want to compare these values to a fixed string to check if the first 5 char matches in 1st set of string (ABCDE*** == ABCDEFGH) and ignore the last 3 variable characters while making sure the length is the same. Eg : if (ABCDE*** == ABCDEDEF) then condition is true, but if (ABCDE*** == ABCDDEFG) then the condition is false because the first 5 char is not same, also if (ABCDE*** == ABCDEFV) the condition should be false as one char is missing.
I'm using the * in fixed string to try to make the length same while comparing.
Does this solve your requirements?
private static bool MatchesPattern(string input)
{
const string fixedString = "ABCDExyz";
return fixedString.Length == input.Length && fixedString.Substring(0, 5).Equals(input.Substring(0, 5));
}
In last versions of C# you can also use ranges:
private static bool MatchesPattern(string input)
{
const string fixedString = "ABCDExyz";
return fixedString.Length == input.Length && fixedString[..5].Equals(input[..5]);
}
See this fiddle.
BTW: You could probably achieve the same using regex.
It's always a good idea to make an abstraction. Here I've made a simple function that takes the pattern and the value and makes a check:
bool PatternMatches(string pattern, string value)
{
// The null string doesn't match any pattern
if (value == null)
{
return false;
}
// If the value has a different length than the pattern, it doesn't match.
if (pattern.Length != value.Length)
{
return false;
}
// If both strings are zero-length, it's considered a match
bool result = true;
// Check every character against the pattern
for (int i = 0; i< pattern.Length; i++)
{
// Logical and the result, * matches everything
result&= (pattern[i]== '*') ? true: value[i] == pattern[i];
}
return result;
}
You can then call it like this:
bool b1 = PatternMatches("ABCDE***", "ABCDEFGH");
bool b2 = PatternMatches("ABC***", "ABCDEF");
You could use regular expressions, but this is fairly readable, RegExes aren't always.
Here is a link to a dotnetfiddle: https://dotnetfiddle.net/4x1U1E
If the string you match against is known at compile time, your best bet is probably using regular expressions. In the first case, match against ^ABCDE...$. In the second case, match against ^...DEF$.
Another way, probably better if the match string is unknown, uses Length, StartsWith and EndsWith:
String prefix = "ABCDE";
if (str.Length == 8 && str.StartsWith(prefix)) {
// do something
}
Then similarly for the second case, but using EndsWith instead of StartsWith.
check this
public bool Comparing(string str1, string str2)
=> str2.StartWith(str1.replace("*","")) && str1.length == str2.Length;
I'm currently attempting to validate a string for an assignment so it's imperative that I'm not simply given the answer, if you provide an answer please give suitable explanation so that I can learn from it.
Suppose I have a string
(1234)-1234 ABCD
I'd like to create a loop that will go through that string and validate the position of the "()" as well as the "-" and " ". In addition to the validation of those characters their position must also be the same as well as the data type. Finally, it must be inside a method.
CANNOT USE REGEX
TLDR;
Validate the position of characters and digits in a string, while using a loop inside of a method. I cannot use REGEX and need to do this manually.
Here's what I have so far. But I feel like the loop would be more efficient and look nicer.
public static string PhoneChecker(string phoneStr)
{
if (phoneStr[0] == '(' && phoneStr[4] == ')' && phoneStr[5] == ' ' && phoneStr[9] == '-' && phoneStr.Length == 14)
{
phoneStr = phoneStr.Remove(0, 1);
phoneStr = phoneStr.Remove(3, 1);
phoneStr = phoneStr.Remove(3, 1);
phoneStr = phoneStr.Remove(6, 1);
Console.WriteLine(phoneStr);
if (int.TryParse(phoneStr, out int phoneInt) == false)
{
Console.WriteLine("Invalid");
}
else
{
Console.WriteLine("Valid");
}
}
else
{
Console.WriteLine("Invalid");
}
return phoneStr;
}
It is still unmaintaible, but still a little better... Note that your code didn't work with your example string (the indexes were off by one).
public static bool PhoneChecker(string phoneStr)
{
if (phoneStr.Length != 16 || phoneStr[0] != '(' || phoneStr[5] != ')' || phoneStr[6] != '-' || phoneStr[11] != ' ')
{
return false;
}
if (!uint.TryParse(phoneStr.Substring(1, 4), out uint phoneInt))
{
return false;
}
if (!uint.TryParse(phoneStr.Substring(7, 4), out phoneInt))
{
return false;
}
// No checks for phoneStr.Substring(12, 4)
return true;
}
Some differences:
The Length check is the first one. Otherwise a short string would make the program crash (because if you try to do a phoneStr[6] on a phoneStr that has a length of 3 you'll get an exception)
Instead of int.Parse I used uint.Parse, otherwise -500 would be acceptable.
I've splitted the uint.Parse for the two subsections of numbers in two different check
The method returns true or false. It is the caller's work to write the error message.
There are various school of thought about early return in code: I think that the earlier you can abort your code with a return false the better it is. The other advantage is that all the remaining code is at low nesting level (your whole method was inside a big if () {, so nesting +1 compared to mine)
Technically you tagged the question as C#-4.0, but out int is C#-6.0
The main problem here is that stupid constraints produce stupid code. It is rare that Regex are really usefull. This is one of the rare cases. So now you have two possibilities: produce hard-coded unmodifiable code that does exactly what was requested (like the code I wrote), or create a "library" that accepts variable patterns (like the ones used in masked edits, where you can tell the masked edit "accept only (0000)-0000 AAAA") and validates the string based on this pattern... But this will be a poor-man's regex, only worse, because you'll have to maintain and test it. This problem will become clear when one month from the release of the code they'll ask you to accept even the (12345)-1234 ABCD pattern... and then the (1234)-12345 ABCD pattern... and a new pattern every two months (until around one and half years later they'll tell you to remove the validator, because the persons that use the program hate them and it slow their work)
I have to check writerId is not equal to 0 or 1. here is what I wrote.
int writerId = foo();
if(writerId != 0 && writerId != 1)
{
// do something
}
Is there any short way to write the same if statement?
This is shorter, but considerably harder to understand:
if ((writerId & ~1) != 0)
The writerId & ~1 operation unsets the least significant bit in the number -- the only two numbers that would be equal to 0 after this operation are 1 and 0, so if the result is not 0 then it must not have been 0 or 1.
However, you are severely sacrificing readability. Sometimes the shortest code is not the most readable. I would stick with what you have.
If readability is a concern when viewing this piece of code.. you could always move it into its own boolean method so that it reads nicer in the context of the other code:
bool IsValid(int writerId) {
return writerId != 0 && writerId != 1;
}
Then your code can at least read a little bit nicer:
if (IsValid(writerId)) {
// do something
}
..I will leave the appropriate naming for the method up to you. I generally do this if there is no easier way to make the code read nicer without it becoming more complex.
You can try this:
if (foo() >> 1 != 0)
{
// do something
}
This happened to be a reoccuring thing in my daily work. I wrote an extension for it at some point:
public static class GenericExtensions
{
public static bool EqualsAny<T>(this T value, params T[] comparables)
{
return comparables.Any(element => object.Equals(value, element));
}
public static bool EqualsNone<T>(this T value, params T[] comparables)
{
return !EqualsAny(value, comparables);
}
}
So instead of (writerId != 0 && writerId != 1) you can write (!writerId.EqualsAny(0, 1)) or (writerId.EqualsNone(0, 1)). In this case, I probably wouldn't use the EqualsNone method, because it actually lowers readability. I might not use the method for this case at all anyway. It mostly helps with readability with long enum names that would cause long or wrapped lines. And as always it's a matter of opinion at any rate. ;)
I'm curious to know if there is such an operator that will allow for the following
Initial line:
if(foo > 1 && foo < 10)
Desired Line: (Variable repetition assumption?)
if(foo > 1 && < 10)
Im looking to educate myself a little on how these operators work at a lower level, explanation as to why not would be much appreciated.
Thanks,
No, there is no such operator in C#. You will have to repeat the variable or expression to compare against.
I don't know the official reason why such an operator does not exist in C# but here's a few thoughts:
No other language (that I know of) has one, as such it's probably not all that useful
All features starts with -100 points, and needs good justification why it needs to be raised above the threshold needed to actually implement it, and will also have to justify doing it before or instead of other features. Since it's so easy to write the expression anyway I doubt it meets all these criteria.
You could (although I don't think this would be a good idea) create an extension method:
void Main()
{
int foo = 5;
if (foo.Between(1, 10))
Debug.WriteLine("> 1 and < 10");
else
Debug.WriteLine("?");
}
public static class Extensions
{
public static bool Between<T>(this T value, T lowNotIncluded, T highNotIncluded)
where T : struct, IComparable<T>
{
return value.CompareTo(lowNotIncluded) > 0 && value.CompareTo(highNotIncluded) < 0;
}
}
But would not recommend that. One question to raise if you want to go the extension method route is how to handle all the combinations of >, >=, <, and <=.
This type of operator does not exist in C#.
But I wouldn't use it anyway because the readability and intention of your code is not very clear. Instead I would use an extension method like this:
// using extension method
int number = 15;
if (number.IsBetween(0, 12))
{
...
}
// definition of extension method
public static bool IsBetween(this int num, int lower, int upper, bool inclusive = false)
{
return inclusive
? lower <= num && num <= upper
: lower < num && num < upper;
}
I have three if statements which they are apparently working on different functions. I wanted to combine them into one function, thus I have to combine the if statement. But I was stuck at how to use the || && and ().
My functions as filters, user can fill in whichever textboxes. On button click event, the code will find those that met criteria. Three of them work well independently, but combining them is very tough. Please bear with me and help me, I am just a very new programmer and no background at all. I am stuck for days. ;(
My filters snapshot:
First:
if (itemAuthor.ToLower() == txtComAuthor.Text.ToString().ToLower())
Second:
if ((!DateTime.TryParseExact(txtComStartDate.Text, "dd/MM/yy", provider, DateTimeStyles.AssumeLocal, out startDate)
|| DateTime.Parse(itemDate, provider, DateTimeStyles.AssumeLocal) >= startDate) &&
(!DateTime.TryParseExact(txtComEndDate.Text, "dd/MM/yy", provider, DateTimeStyles.AssumeLocal, out endDate)
|| DateTime.Parse(itemDate, provider, DateTimeStyles.AssumeLocal) <= endDate))
Third:
if (txtComKeyword1.Text != (String.Empty) && itemDescription.ToLower().Contains(txtComKeyword1.Text.ToLower()) ||
txtComKeyword2.Text != (String.Empty) && itemDescription.ToLower().Contains(txtComKeyword2.Text.ToLower()) ||
txtComKeyword3.Text != (String.Empty) && itemDescription.ToLower().Contains(txtComKeyword3.Text.ToLower()) ||
txtComKeyword4.Text != (String.Empty) && itemDescription.ToLower().Contains(txtComKeyword4.Text.ToLower()))
Whether to use || or && depends on whether you want the meaning at least one condition is true (use ||) or all conditions must be true (use &&).
If you need to mix both meanings, use () to cause conditions to be evaluated against each other, e.g.
if ( (a && b) || (c && d))
means if both a and b are true or both c and d are true.
It makes for easier-to-read and maintain code if you define separate booleans for each portion of the compound logic. There is no performance difference.
bool condition1 = !DateTime.TryParseExact(txtComStartDate.Text, "dd/MM/yy", provider, DateTimeStyles.AssumeLocal, out startDate);
bool condition2 = DateTime.Parse(itemDate, provider, DateTimeStyles.AssumeLocal) >= startDate);
bool condition3 = !DateTime.TryParseExact(txtComEndDate.Text, "dd/MM/yy", provider, DateTimeStyles.AssumeLocal, out endDate);
bool condition4 = DateTime.Parse(itemDate, provider, DateTimeStyles.AssumeLocal) <= endDate);
if ((condition1
|| condition2 &&
(condition3
|| condition4)
It will help you understand if you break each one of these clauses into functions and divvy up the complexity accordingly. Smaller pieces are easier to work with, and more maintainable in the long run. When you evolve as a programmer, you will eventually not use if statements for this at all, but rather leverage the power of polymorphism.
For now, begin by piecing things apart.
public void btnAnalyze_onClick(){
List<Item> results = new ArrayList<Item>();
if(txtComAuthor.Text != String.Empty)
{
List<Item> matched = filterByAuthor(txtComAuthor.Text);
results.addRange(matched);
}
if(txtComStartDate.Text != String.Empty)
{
List<Item> matched = filterByStartDate(txtComStartDate.Text);
results.addRange(matched);
}
// do the same for the others
return results;
}
public List<Item> filterByAuthor(String desiredAuthorName){
List<Item> matches = new ArrayList<Item>();
//have your data access piece here, from DB/Excel/whatever.
List<Item> candidates = ...
foreach(Item candidate in candidates){
if(candidate.ToLower() == desiredAuthorName){
matches.add(candidate)
}
}
return matches;
}
Experienced programmers will realize that there's a lot of duplication here and will have fits at the violations of DRY and performance. That's ok. It can be refactored. For a novice, this will be the easiest style to understand.
If you follow this style, it should be readily apparent where you need to do the filtering. Basically, you will need to replace the if statement in the foreach loop with the condition for the text field you're thinking about.
But you shouldn't need to add a bunch of clauses together doing this because you've broken things apart a little better. If you still find you need a few nested ifs, break it down further into even smaller functions.
When in doubt about logical grouping, put parentheses around every pair of operations. That way you know how the pairs will be combined.
if ((A && B) || (C && D)) will evaluate the (A && B) and (C && D) segments, then "or" those intermediate results together to produce the final value.
For further reading, search for commutative, associative, and distributive properties of boolean logic.
As far as I can tell, you want to evaluate all 3 at the same time, but simply adding them into one big line will be hard to read or maintain. I'd recommend setting seperate bool values for each of your previous ifs:
bool firstIf = (itemAuthor.ToLower() == txtComAuthor.Text.ToString().ToLower());
Then comparing all 3 in one statement:
if (firstIf && secondIf && thirdif)
{
Console.WriteLine("It works!");
}
This way, it is easier to make changes later if need be, and you can still read the code.