Jason
Jason

Reputation: 3689

Checking if every character in a c# string is the same character

Starting with any string, I need to ascertain whether that string comprises one or more instances of only a specified single character. For example "£££££" would pass my test, "wertf" would fail. The approach I have taken is as follows:

string source = "any string";
char[] candidate = source.ToCharArray();
char validCharacter = '£';

    if (candidate.Length > 0)
    {
        // (code removed) if candidate length = 1 then just test candidate[0] against validCharacter
        bool isValid = true;
        int index = 0;

        while (index < candidate.Length - 1)
        {
            if (candidate [index] != validCharacter )
            {
                isValid = false;
                break;
            }

            index++;
        }

        if (isValid)
        {
            // success, do what needs doing
        }
    }

This works, as you would expect, but I can't help but feel that I might be missing a trick here. Is there a better, more concise, way of doing this that doesn't sacrifice the clarity of the above?

Upvotes: 0

Views: 216

Answers (9)

Oliver
Oliver

Reputation: 9002

Use Distinct() to remove duplicates and compare the character counts.

var pass = mystring.Count() > mystring.Distinct().Count();

EDIT

I misread and thought it was a duplicate of any character in the test string. The following is correct for "one or more instances of only a single character".

mystring.Distinct().Count() == 1

Upvotes: 2

slim
slim

Reputation: 41213

if(Regex.IsMatch(candidate, "^£+$")) {
   // whatever it is you want to do
}

... or of course ...

if(Regex.IsMatch(candidate, "^" + Regex.Escape(validChar) + "+$") { ... }

Regex.Escape() is there in case validChar is a character with meaning in regular expressions, like *, . etc.

These are short, declarative (as long as the reader understands regular expressions), efficient, performance scales to long strings, and the idiom extends to more complicated patterns.

Upvotes: 0

Habib
Habib

Reputation: 223187

Use Enumerable.All<TSource> Method

bool result = (str.Length > 0 && str.All(r=> r == str[0]));

This would be efficient than using Distinct and Count()

For your case it can be:

string source = "any string";
char validCharacter = '£';
bool result = source.Length > 0 && source.All(r=> r == validCharacter);

Upvotes: 3

cuongle
cuongle

Reputation: 75296

You just check with simpler code whether a string has the same character:

if (source.Distinct().Count() == 1)
{
    // Pass
}

Edit:

If you need to check string comprises one or more instances of only a specified single character, you can use All:

if (input.All(c => c == specificChar))
{
    // Pass
}

Upvotes: 9

Oded
Oded

Reputation: 498904

Here is one way to do this:

if(source[0] != validCharacter) return false;

bool isValid = true;
for(int i = 1 ; i < source.Length; i++)
{
  if(validCharacter != source[i])
  {
    isValid = false;
    break;
  }
}

Things to note: immediate fail if the first character doesn't match. string already implements IEnumerable<char>, so no need to use ToCharArray with the extra allocations. The loop starts at index 1, always comparing to the first item and breaking as soon as it fails.

This is likely to be more efficient for long strings than Distinct.

Upvotes: 2

Rob Church
Rob Church

Reputation: 6943

Your code is probably going to be the fastest, you could compact it somewhat by using a for instead of a while

for (int i = 0; i < source.Length; i++) {
    // existing equality check
}

Alternatively, here's another inefficient but more compact method (as it creates a new string in memory and checks against):

if (source == new String('£', source.Length)) {
    // valid
}

Upvotes: 1

sexta13
sexta13

Reputation: 1568

you can try this:

 string str = "test";
            char b = '£';
            bool isValid = false;
            foreach (char a in str) 
            {
                if (!a.Equals(b)) 
                {
                    isValid = false;
                }
            }

Upvotes: 0

Knaģis
Knaģis

Reputation: 21475

In your algorithm you don't need the .ToCharArray(). Just retrieve the character using source[index]. This way you will only be reading the memory and reading every character just once.

Your code is the optimal solution. There are many tricks using LINQ but most will perform much worse. Any tricks with code like source.Trim(source[0]) will result into unnecessary creation of new strings and thus also in worse performance.

See the answer from Oded♦ that shortens your existing code.

Upvotes: 1

hattenn
hattenn

Reputation: 4399

string test1 = "Test";
string test2 = "TTTT";

test1.All(a => a == test1[0]);
test2.All(a => a == test2[0]);

Upvotes: 1

Related Questions