How do I check if a number string is in running sequence - c#

Is there a regex (or any other way) to check if a numbers in a string is in running sequence?
E.g.,
"123456" will return true
"456789" will return true
"345678" will return true
"123467" will return false
"901234" will return false

If all your sequences are composed of single-digit numbers, then you can solve this by observing that all correct sequences must be substrings of the longest such sequence, i.e. of "0123456789". So the check can be done like this:
bool res = "0123456789".Contains(str);
Demo on ideone.

How about this:
text.Skip(1).Zip(text, (c1, c0) => new { c1, c0 }).All(c => c.c1 - c.c0 == 1)

Related

Why my method is returning the result in Boolean?

I have the following method which returns either true or false but I do not understand why.
public bool Check(string s)
{
return s.Length == 8 && s.Count(Char.IsUpper) == 1 && s.Any(Char.IsDigit);
}
Please help me understand.
Your code amended (it will crash on s == null) and commented:
public bool Check(string s)
{
return // return true if and only if
s != null && // s is not null and
s.Length == 8 && // s has Length of 8 and
s.Count(Char.IsUpper) == 1 && // s has exactly 1 Upper case letter and
s.Any(Char.IsDigit); // s has at least one digit
}
You should read it like:
public bool Check(string s)
{
// It would be worth to check for null
if(s == null)
throw new ArgumentNullException(nameof(s));
// because of the && all criteria must be true
return
s.Length == 8 // is the length 8?
&& s.Count(Char.IsUpper) == 1 // the must be one uppercase character? (the trick is to execute the IsUpper for each character)
&& s.Any(Char.IsDigit); // Does it contain any digit? (same here)
}
Instead of using string s, you should give it better names, like string password. Same for the method name... CheckPasswordConstraints
In your Check(string s) method you are check below three conditions.
s.Length == 8 :
In this condition equality operator is used to check condition.
This condition will return true if s.Length is 8 otherwise false
s.Count(Char.IsUpper) == 1 :
In this condition, again equality operator is used to check condition, but with .Count().
if string s contains exact 1 upper case letter then it will return true otherwise false.
s.Any(Char.IsDigit):
Linq .Any() returns boolean true, if string contains atleast one digit.
&& operator to combine three different conditions,
&& returns true if all conditions are true. && returns false if any of
the condition is false
true && true && true => true
false && true && true => false
s.Count and s.Any are methods, which counts (or signals if there are any elements in collection), with regard to method passed as an argument, which has to accept element of a colletion as a parameter and return true.
Since string is collection of chars, you can use Any and Count.
Char.IsDigit and Char.IsUpper are just methods of signeature:
bool MethodName(char c);
so they can be used in LINQ methods.
So, to sum up:
Count(Char.IsUpper) - counts upper characters
Any(Char.IsDigit) - signals, if we have at least one digit in string.
You are right not to understand this method, because the method name "Check" is not descriptive enough. Check what exactly? The method name should indicate what it is checking, or at the very least have comments which explain why and what it's doing.
Either way, the method is checking that the provided string:
Is 8 characters long
Has exactly one uppercase character
Has at least one digit
This method has 3 conditions:
s.Length == 8
this checks whether the length of string is exactly 8 or not.
s.Count(Char.IsUpper) == 1
this checks whether the total number of upper case letters in string is exactly equal to 1.
Here an overload of Count is being used which expects a predicate Count<TSource> (Func<TSource,bool> predicate) and Char.IsUpper is the predicate which is being passed.
Refference:
Count(predicate)
Char.IsUpper
s.Any(Char.IsDigit) this checks whether is there any digit in the string or not. Reference:
Char.IsDigit
So, when all of these conditions are true , the Check method would return true.

How to find index of a value in array of char?

Suppose I have this array of char:
private char[] _alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
.ToCharArray();
I want find the index of the character B, so the code must return 1.
I wrote this method:
public int? GetCharIndex(string code)
{
return _alpha.FirstOrDefault(c => c.ToString() == code.ToUpper());
}
where code is b. The result of GetCharIndex is: 66, why I get this result?
Thanks in advance for any help.
use Array.IndexOf
https://learn.microsoft.com/en-us/dotnet/api/system.array.indexof?view=netframework-4.7.2
The 66 you are getting is 'B' ascii value.
The FirstOrDefault function returns the actual item (B) not the index.
So:
int index = Array.IndexOf(_alpha, code.ToUpper());
As you've mentioned, you'd like to use Linq. The Select in LINQ has an override that let's you expose the index. Getting the first matching value will give us the index of the occurrence. You can also replace the .FirstOrDefault() to .ToList() if you want all indexes on the match.
ToList
char[] _alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToArray();
var code = "b";
var key = _alpha.Select((s, i) => new { i, s })
.Where(t => t.s.ToString().ToUpper() == code.ToUpper())
.Select(t => t.i)
.ToList();
Alternatively the above can also be written as
FirstOrDefault
return _alpha.Select((s, i) => new { i, s }).FirstOrDefault(t => t.s.ToString().ToUpper() == code.ToUpper()).i;
Why I get this result?
Nullable<Char> is implicitly convertible to Nullable<Int32> because Char is implicitly convertible to Int32. That happens in your return statement. You're returning the character from the array if found.
Where people are saying ASCII code, they mean character code; in particular, since .NET uses the UTF-16 character encoding of the Unicode character set the UTF-16 code unit value.
BTW—VB4/5/6/A/Script, Java, JavaScript, … also use UTF-16 for text datatypes.
To use standard LINQ operators, choose one that supplies an index like Select:
Char[] _alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
Func<Char, StringComparison, Int32?> GetIndexOf = (code, comparisonType) => {
var value = code.ToString();
return _alpha
.Select((c, i) => c.ToString()
.Equals(value, StringComparison.InvariantCultureIgnoreCase) ? i : (Int32?)null)
.FirstOrDefault(i => i.HasValue); } ;
Debug.Assert(1 == GetIndexOf('B', StringComparison.InvariantCultureIgnoreCase));
Debug.Assert(null == GetIndexOf('3', StringComparison.InvariantCultureIgnoreCase));
And, you do have to decide what you really intend by your ".ToUpper". As a question/code review issue, it's unclear. It would be better to write your question and code (or at least as a code comment) in such a way as it explains what the proper culture is for letter case comparison. You used one that depends on the program's current culture, which is initialized from the user's culture at the time the program started.

Maximum number of occurrences a character appears in an array of strings

In C#, given the array :
string[] myStrings = new string[] {
"test#test",
"##test",
"######", // Winner (outputs 6)
};
How can I find the maximum number of occurrences that the character # appears in a single string ?
My current solution is :
int maxOccurrences = 0;
foreach (var myString in myStrings)
{
var occurrences = myString.Count(x => x == '#');
if (occurrences > maxOccurrences)
{
maxOccurrences = occurrences;
}
}
return maxOccurrences;
Is their a simplier way using linq that can act directly on the myStrings[] array ?
And can this be made into an extension method that can work on any IEnumerable<string> ?
First of all let's project your strings into a sequence with count of matches:
myStrings.Select(x => x.Count(x => x == '#')) // {1, 2, 6} in your example
Then pick maximum value:
int maximum = myStrings
.Select(s => s.Count(x => x == '#'))
.Max(); // 6 in your example
Let's make an extension method:
public static int CountMaximumOccurrencesOf(this IEnumerable<string> strings, char ch)
{
return strings
.Select(s => s.Count(c => c == ch))
.Max();
}
However there is a big HOWEVER. What in C# you call char is not what you call character in your language. This has been widely discussed in other posts, for example: Fastest way to split a huge text into smaller chunks and How can I perform a Unicode aware character by character comparison? then I won't repeat everything here. To be "Unicode aware" you need to make your code more complicate (please note code is wrote here then it's untested):
private static IEnumerable<string> EnumerateCharacters(string s)
{
var enumerator = StringInfo.GetTextElementEnumerator(s.Normalize());
while (enumerator.MoveNext())
yield return (string)enumerator.Value;
}
Then change our original code to:
public static int CountMaximumOccurrencesOf(this IEnumerable<string> strings, string character)
{
return strings
.Select(s => s.EnumerateCharacters().Count(c => String.Equals(c, character, StringComparison.CurrentCulture))
.Max();
}
Note that Max() alone requires collection to don't be empty (use DefaultIfEmpty() if collection may be empty and it's not an error). To do not arbitrary decide what to do in this situation (throw an exception if it should happen or just return 0) you can may make this method less specialized and leave this responsibility to caller:
public static int CountOccurrencesOf(this IEnumerable<string> strings,
string character,
StringComparison comparison = StringComparison.CurrentCulture)
{
Debug.Assert(character.EnumerateCharacters().Count() == 1);
return strings
.Select(s => s.EnumerateCharacters().Count(c => String.Equals(c, character, comparison ));
}
Used like this:
var maximum = myStrings.CountOccurrencesOf("#").Max();
If you need it case-insensitive:
var maximum = myStrings.CountOccurrencesOf("à", StringComparison.CurrentCultureIgnoreCase)
.Max();
As you can now imagine this comparison isn't limited to some esoteric languages but it also applies to invariant culture (en-US) then for strings that must always be compared with invariant culture you should specify StringComparison.InvariantCulture. Don't forget that you may need to call String.Normalize() also for input character.
You can write something like this. Note the usage of DefaultIfEmpty, to not throw an exception if myStrings is empty, but revert to 0.
var maximum = myStrings.Select(e => e.Count(ee => ee == '#')).DefaultIfEmpty().Max();
You can do that with Linq combined to Regex:
myStrings.Select(x => Regex.Matches(x, "#").Count).max();

C#, check string if 'a letter' is followed by 'a letter'

Let say, * has to be followed by &.
For example,
string asd = "Mother*&Mother*&Son";
// which is "Mother+ "*&" + "Mother" + "*&" + "Son"
// This is correct string.
Bad example,
string asd = "Mother*Mother*&Son";
string asf = "Mother**&Mother*&Son";
string asg = "Mother*&*Mother*&Son";
How can I check if the string is correct or not in C#?
EDIT
based on the usage of Regex that you guys introduced, I have a side question. I am actually using comma(,) instead of asterisk(*) and quotation mark(") instead of ampersand(&).
In C#, (Let me use one of the guy's example)
Regex.IsMatch("Mother,\",Mother,\"Son", #"\,(?!")")
//won't work.. any idea?
I also tried
Regex.IsMatch("Mother,\",Mother,\"Son", #"\,(?!\")")
//not work, neither
Find failures by looking for any asterisk (*) not followed by an ampersand (&):
Regex.IsMatch("Mother*&*Mother*&Son", #"\*(?!&)")
You can use regex. But it will be easier to find when string is not correct and then just negate the result.
I would look for any * which is not followed by &. The regex should look like: (\*[^&])|(\*$)
Simple test code:
var inputs = new[] {
"Mother*&Mother*&Son",
"Mother*Mother*&Son",
"Mother**&Mother*&Son",
"Mother*&*Mother*&Son",
"Mother*&Mother*&Son*"
};
var regex = new Regex(#"(\*[^&])|(\*$)");
var isOK = inputs.Select(x => !regex.IsMatch(x)).ToList();
Returns a list of results, which contains true, false, false, false, false.
For something like this, I'd favor the direct approach, rather than using Regex. This will make at most one pass through the entire string, which should be more efficient than a Regex.
/// Return true if every instance of 'a' in the string is followed by 'b'.
/// Also returns true if there are no instances of 'a' in the string.
/// Returns false if there exists any 'a' that is not followed by 'b'.
public static bool IsTwoCharSequence(string s, char a, char b)
{
if(String.IsNullOrEmpty(s)) return true;
if(s[s.Length - 1] == a) return false; // ends in a, not followed by b. Condition failed.
int index = s.IndexOf(a); // find the first a
while(index != -1)
{
if(s[index + 1] != b) return false; // a not followed by b.
index = s.IndexOf(a, index + 1);
}
return true; // either no a, or all a followed by b.
}
Edit: In addition, you don't need to worry about how to quote your separator characters, when they're also special characters within a Regex.
Edit 2: Yes, it's two loops, but look at what each loop is doing.
The inner loop, the one inside of String.IndexOf, will iterate through characters until it finds the passed-in character. The first call to IndexOf (the one outside the while loop) starts searching at the beginning of the string, and the subsequent ones start at that index, and continue searching to the next match, or to the end. Overall, we've made just one pass over the entire string.
Here's another method, which is similar in concept to the above one, but where the 'iterate the entire string only once' is more explicit.
public static bool IsTwoCharSequence(string s, char a, char b)
{
if (String.IsNullOrEmpty(s)) return true;
bool foundA = false;
foreach (char c in s)
{
if (foundA && c == b)
foundA = false;
else if (foundA)
return false;
else if (c == a)
foundA = true;
}
if (foundA) return false; // 'a' was the last char in the string.
return true;
}
Use Regular expressions and check that the number of matches for *& is the same as the number of *s
code of the top of my head, may not compile but try:
Regex r = new Regex(#"\*&");
Regex r2 = new Regex(#"\*");
if (r.Matches(myString).Count == r2.Matches(myString).Count) //success!

How do I Compare two char[] arrays for equivalency?

Right now, I have two char arrays, foo1[] and foo2[]. When I convert them to string and output to the console, they BOTH appear as bar. I know that I can do something like this:
int g;
for (int i=0;i<length.foo1;i++) { // loop from 0 to length of array
if (foo1[i]=foo2[i]) { // if foo1[0] and foo2[0] are the same char
g++; // increment a counter by 1
}
else // otherwise...
{
i=100; // set i to something that will halt the loop
}
if (g = length.foo1) { // if the incremented counter = length of array
return true; // arrays are equal, since g only increments
} // in the case of a match, g can ONLY equal the
else { // array length if ALL chars match
return false; // and if not true, false.
to compare them letter by letter, but I'm guessing there's an easier way. Interestingly, most of the googling I do for comparing char[] for eqivalency c# and similar keywords results in a whole mess of info about comparing STRING arrays, or comparing string or char arrays when PART of the array matches something or another...I've not been able to find anything about easy ways of testing char arrays as being equal. Is stepping through each array the best way? or is there some way to compare if foo1=foo2 or foo1==foo2? Neither of those worked for me.
Basically, I need to test if char foo1[] and char foo2[] are BOTH {B,A,R}
You are possibly looking for:
foo2.SequenceEqual(foo1)
I think you can use the SequenceEquals to compare the arrays, even though checking both lengths at first has better performance.
foo1.ToList().Intersect(foo2.ToList())
you can make a function of yours which will be faster then first converting char[] to string then compare two strings.
1. First compare length of the arrays if they are not equal return false.
2. start looping through and compare each char, If you find any diff return false else after the loop return true.
if(foo1.Length != foo2.Length){ return false;}
for(int i=0;i<foo1.Length;i++){
if(foo1[i] != foo2[i]){ return false;}
}
return true;
string s = new string(foo1);
string t = new string(foo2);
int c = string.Compare(s, t);
if(c==0){
//its equal
}

Categories

Resources