2
\$\begingroup\$

I did this small project where there are six one-liner anonymous methods that can swap case of a given string of any length. For example "heLLo, woRLd" ==> "HEllO, WOrlD". I used this string as the example to demonstrate how each of the function works. This string "heLLo, woRLd" can simply be replaced with Console.ReadLine() to get user anticipated inputs. I understand one-liners are not readable and maybe not considered good practice, and used variable names are not proper as well. This whole project was for fun. I believe that way I can learn more. My expectation is that someone can tell me if there are more ways to do this case-swapping (of course, has to be one-liner)?. I think I used 3 (kinda) algorithms to do the swapping. Moreover, all of the one-liners are void functions and all the succeeding functions are shorter than the preceding ones.

using System;
using System.Linq;

class x
{
    static void Main(string[] args)
    {
        // one-liner string swapcase
        (new Action<string>(delegate (string x) { foreach (char i in x) { char b = i; b^= char.IsLetter(b) ? (char)32 : (char)0; Console.Write(b); } }))("heLLo, woRLd");

        Console.WriteLine();

        //one-liner string swapcase2
        (new Action<string>(delegate (string x) { foreach (char i in x) { Console.Write(char.IsUpper(i) ? char.ToLower(i) : char.ToUpper(i)); } }))("heLLo, woRLd");

        Console.WriteLine();

        // one-liner string swapcase3
        ((Action<string>)(delegate (string x) { foreach (char i in x) { Console.Write(char.IsUpper(i) ? char.ToLower(i) : char.ToUpper(i)); } }))("heLLo, woRLd");

        Console.WriteLine();

        //one-liner string swapcase4
        ((Action<string>)((x) => { foreach (char i in x) { Console.Write(char.IsUpper(i) ? char.ToLower(i) : char.ToUpper(i)); } }))("heLLo, woRLd");

        Console.WriteLine();

        //one-liner string swapcase5
        "heLLo, woRLd".ToList().ForEach(i => Console.Write(char.IsUpper(i) ? char.ToLower(i) : char.ToUpper(i)));

        Console.WriteLine();
        //one-liner string swapcase6
        "heLLo, woRLd".ToList().ForEach(i => Console.Write(i^= char.IsLetter(i) ? (char)(1 << 5) : (char)0));
        Console.ReadLine();
    }
}
\$\endgroup\$
  • \$\begingroup\$ You can also loop with foreach (var c in "heLLo, woRLd") {...}. \$\endgroup\$ – Xiaoy312 Jun 26 '18 at 18:50
  • \$\begingroup\$ Excluding your last 2 examples, all the rest are not 1 liners, if you consider them 1 line, then you might as well call your entire file 1 liner. Also I wouldn't call a small change of anonymous methods vs lambda, a different way of doing it. \$\endgroup\$ – Denis Jun 27 '18 at 12:02
  • \$\begingroup\$ @Denis could u care to explain why they r not one-liners? From taking input to printing output was done in a single line. If u don’t consider lambda a way of doing one-liner than plz come up with a better explanation. \$\endgroup\$ – A J Jun 27 '18 at 16:03
9
\$\begingroup\$

I find your code amusing but since this is not Code Golf but Code Review I'll review it from our perspective this is, as clean-code first.

Even if you try to write compact code you should not use magic exressions and sacrifice readability. Instead encapsulate them in (local) function or use proper constants. You also should not use unrelated variable names like here i for char where c would be more appropriate. Alternatively you can also use the Aggregate to loop over the string and collect the results in a StringBuilder. The (char)0 can be replaced with the much prettier default.

const char caseOffset = (char)(1 << 5);

char SwapCase(char c) => c ^= (char.IsLetter(c) ? caseOffset : default);

var result = 
    "heLLo, woRLd"
        .Aggregate(
            new StringBuilder(), 
            (b, c) => b.Append(SwapCase(c))
        ).ToString();

One more option would be to use Select and new string and feed it with the new result.

var result = new string("heLLo, woRLd".Select(SwapCase).ToArray())

The advantage of Select is that you don't need the => lambda anymore.

\$\endgroup\$
  • \$\begingroup\$ Again, our definitions of code-golf will have to differ! You can have a +1 if you add a brief comment to this fine answer about Unicode; there isn't much more I'd say that would warrant a full answer ;) \$\endgroup\$ – VisualMelon Jun 26 '18 at 19:14
  • \$\begingroup\$ Thanks, I mentioned before that it was for fun. So, I didn’t consider readability. Your solutions are interesting, but I was expecting to have one-liners (from taking input to printing output in one line. But I appreciate your feedback. \$\endgroup\$ – A J Jun 26 '18 at 19:15
  • \$\begingroup\$ @VisualMelon I quess I'm not going to earn that +1 :P as I have no idea how to deal with unicode exactly (right now) let's wait for Adrianno Repetti - he's the unicode expert - I know that it won't work for every language and to be honest... I naively assumed the english alphabet. Would I have to work with other languages I'd probably go with ToUpper/Lower. \$\endgroup\$ – t3chb0t Jun 26 '18 at 19:22
  • 1
    \$\begingroup\$ @t3chb0t oh, well have it anyway then! I'll await Adrianno Repetti to tell us how it should be done properly instead of making something up :P \$\endgroup\$ – VisualMelon Jun 26 '18 at 19:24
  • \$\begingroup\$ SwapCase should be an extension method on char and should use IsUpper, ToUpper, and ToLower to get the job done. \$\endgroup\$ – David Conrad Jun 26 '18 at 20:55
0
\$\begingroup\$

First, I want to thank @t3chb0t for giving such concrete feedback; thanks to this person I was able to have more ways to do the swapping of this above mentioned string. I am posting this as an answer since none else contributed any actual one-liners to my question.

//one-liner string swapcase7 ***idea from @t3chb0t***
Console.WriteLine(new string("heLLo, woRLd".Select(i => i^= char.IsLetter(i) ? (char)(1 << 5) : default).ToArray()));

//one-liner string swapcase8 ***idea from @t3chb0t***    
Console.WriteLine("heLLo, woRLd".Aggregate(new StringBuilder(), (b, o) => b.Append(((Func<char, char>)((a) => { a ^= char.IsLetter(a) ? (char)(1 << 5) : default; return a; }))(o))).ToString());

//one-liner string swapcase9 ***my own understanding of LINQ***
Console.WriteLine(new string((from i in "heLLo, woRLd" select ((Func<char, char>)((a) => { a ^= char.IsLetter(a) ? (char)(1 << 5) : default; return a; }))(i)).ToArray()));
\$\endgroup\$
  • 1
    \$\begingroup\$ Since OP apparently doesn't need a newline in the one-liner: Console.Write accepts a char[], so you save the Line and don't need the new string(char[]) \$\endgroup\$ – Corak Jun 27 '18 at 8:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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