6
\$\begingroup\$

I was given a simple requirement for reversing a string. The requirement is as follows:

In any programming language, create an input that accepts "My name is Albert McDonald." and outputs the reversed value "Ym eman si Trebla DlAnodcm."

I got it to work like this:

string expectedInput = "My name is Albert McDonald.";

//Prompt the user to enter "My name is Albert McDonald."
Console.WriteLine("Please enter the sentence \"" + expectedInput + "\"");
Console.WriteLine();

//Wait for the users input.
string inputText = Console.ReadLine();

//Convert the input to a char array.
List<char> characters = inputText.ToList<char>();

//Get the list of uppercase indexes
List<int> upperIndexes = new List<int>();
for (int index = 0; index < characters.Count; index++)
{
    if (Char.IsUpper(characters[index]))
        upperIndexes.Add(index);
}

//Remove the period at the end
inputText = inputText.Substring(0, inputText.Length - 1);

//Get the reversed array of words.
string[] words = inputText.Split(' ').Reverse().ToArray();

//Join the array back to a string.
string revesedWords = string.Join(" ", words);

//Reverse the entire string and make it all lower case.
string result = new string(revesedWords.Reverse().ToArray()).ToLower();
StringBuilder sb = new StringBuilder(result);

//Change the case of the original index
foreach (int index in upperIndexes)
{
    char newCharacter = char.Parse(result.Substring(index, 1).ToUpper());
    sb[index] = newCharacter;
}

//Output the resutlt
Console.WriteLine("Your name in reverse by word is: \"" + sb.ToString() + ".\"");
Console.WriteLine();

//Inform the user how to close the screen.
Console.WriteLine("Press any key to close the screen.");
Console.ReadLine();

Is there a better way in terms of lines of code and performance-wise?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ So, each word is reversed separately? How exactly is a ”word” defined? For example, should 123 considered as a word? What about ?!? \$\endgroup\$
    – svick
    Commented Apr 22, 2013 at 14:38

2 Answers 2

7
\$\begingroup\$

If you aim for fewer lines of code, you could of course put everything into a single line, but that would not helpful at all.

However, you could shorten your code a bit by using a simple regular expression and some linq-fu, something like:

var s = yourInputString;

// split string into words
var splitted = Regex.Split(s, @"(\W)").Select(r => r.AsEnumerable()).ToArray();

// reverse each word
var reversed = splitted.Select(sp => sp.Reverse().ToArray());

// adjust case
var zipped = splitted.Zip(reversed, (a, b) => string.Join("", a.Select((c, i) => char.IsUpper(c) ? 
                                                                                 char.ToUpper(b[i]) : 
                                                                                 char.ToLower(b[i]))));

// join back to string
var result = string.Join("", zipped);

I would not care about performance in this case, because it would be pointless.

Also, reversing a string with Reverse().ToArray() will corrupt your string if it contains surrogate characters, but this is probably out of scope of your task.

\$\endgroup\$
1
  • \$\begingroup\$ Is the Where() necessary? I think it won't actually affect the output. \$\endgroup\$
    – svick
    Commented Apr 22, 2013 at 14:42
1
\$\begingroup\$

My algorithm is roughly the same. However it changes some things that you might find quite obvious after reading it.

    static string ReverseString(string str)
    {
        string[] arr = str.Split(' ');
        string result = "";

        foreach (var s in arr)
        {
            for (int i = s.Length - 1; i >= 0; i--)
            {
                if (Char.IsUpper(s[s.Length - 1 - i]))
                    result += s[i].ToString().ToUpper();
                else
                    result += s[i].ToString().ToLower();
            }
            result += " ";
        }

        return result;
    }

Another thing that might be helpful is knowing whether punctuation symbols are part of the words or not. That's easy to catch though.

\$\endgroup\$
2
  • \$\begingroup\$ Could you explain what exactly did you change? \$\endgroup\$
    – svick
    Commented Apr 22, 2013 at 18:52
  • \$\begingroup\$ well for instance I don't use .Reverse() which saves me one method call (almost nothing) but more important allows me not to use an index list and saving me another loop, although is still O(n). \$\endgroup\$ Commented Apr 22, 2013 at 19:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.