読者です 読者をやめる 読者になる 読者になる
ようこそ。睡眠不足なプログラマのチラ裏です。

モテようとして、C#でXOR使ってリバースしている奴がいたんですよ

アルゴリズム C# C#2.0 C#3.0

いろいろなリバースのアルゴリズムを見てみましよう。
まずは表題のリバースのアルゴリズムについて、どうぞ。

なんとなくモテようとしている感のあるリバース

モテようとして、C#でXOR使ってリバースしている奴がいたんですよ・・(以下略)。


こんな感じで

        public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            int len = s.Length - 1;
            for (int i = 0; i < len; i++, len--)
            {
                charArray[i] ^= charArray[len];
                charArray[len] ^= charArray[i];
                charArray[i] ^= charArray[len];
            }
            return new string(charArray);
        }

もちろん要件は満たしているし、それほど遅いアルゴリズムでもないので、
私的にはギリギリセーフなんですが、なんとなくやっちまってる感が・・ね。
どうも無理にXOR使ってスワップをして「モテ」を意識しているようです。
嫌いじゃないですがちょっとキモイです(笑)



新人くんにありがちなリバース

        public static string Reverse(string s)
        {
            return new string(s.ToCharArray().Reverse().ToArray());
        }

完全にやっちまってますね。イテリセンス利きまくりのIDEに飼いならされた新人が
「.」押して出てきたやつを次々につなげたらリバースできちゃったよー的な。
これは、超おそおそアルゴなので論外です。新人じゃない場合は・・・\(^o^)/


VB.NET厨寄りC#erにありがちなリバース

        public static string Reverse(string s)
        {
            return Microsoft.VisualBasic.Strings.StrReverse(s);
        }

StrReverseキタコレ。まぁ、間違ってはいないんだけどね・・。
車輪の再発明はしない的理論だよ」というのであれば、そのまま使え、と。
ちったあ、頭つかいましょうよ、と思っちゃいますね。



一般的によく書かれてそうなリバース

        public static string Reverse(string s)
        {
            char[] charArray = new char[s.Length];
            int len = s.Length - 1;
            for (int i = 0; i <= len; i++)
                charArray[i] = s[len - i];
            return new string(charArray);
        }

ノーマルなC#erが最も書きそうな感じです。
教科書通り的な雰囲気があります。特に文句はありません。
書けといわれたら、自分もたぶんこれ書きます。


別によいんだけど、なんとなく残念なリバース

        public static string Reverse(string s)
        {
            char[] arr = s.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }

ノーマルなC#erが割と書きそうな感じです。
確かに、その発想もあるよね。悪くは無いです。あると思います。
そうも思うんだけど、なんとなく賛同できない俺ガイル。


StringBuilderに洗脳されている残念な人のリバース

        public static string Reverse(string s)
        {
            char[] cArray = s.ToCharArray();
            StringBuilder reverse = new StringBuilder();
            for (int i = cArray.Length - 1; i > -1; i--)
            {
                reverse.Append(cArray[i]);
            }
            return reverse.ToString();
        }

間違ってはいないんだけど、StringBuilder使えばいいっちゅーもんでもない。
とりあえず、洗脳を解いてあげたい。


人とは毛色が違いますね・・。正直やめて欲しい個性的なリバース

        public static string Reverse(string s)
        {
            Stack<string> stack = new Stack<string>();
            for (int i = 0; i < s.Length; i++)
                stack.Push(s.Substring(i, 1));
            string ns = string.Empty;
            for (int i = 0; i < s.Length; i++)
                ns += stack.Pop();
            return ns;
        }

これはひどい低速アルゴですね。
スタック使っちゃいますか。そうですか、わかりません。
基本的なところから再教育が必要かもしれません。


がんばったと決して褒めたくない再帰的なリバース

       public static string Reverse(string s, int length)
        {
            if (length == 1) return s;
            return Reverse(s.Substring(1, s.Length - 1), --length) + s[0].ToString();
        }

これもひどい低速アルゴです。ダサいです。
思考的ベクトルの方向が全くわかりません。本当にありがとうございました。


にわか仕込みラムダ厨による超低速リバース

        public static string Reverse(string s)
        {
            Func<string, string> f = null;
            f = x => x.Length > 0 ? f(x.Substring(1)) + x[0] :
                     string.Empty;
            return f(s);
        }

ラムダで書きゃーいいってもんじゃないです。
見なかったことにしてあげるので、今すぐ書き直してください。
できれば死なない程度に死んでください(^-^)


様々なリバースを見てきましたが、まだ飽き足らないあなたへ

unsafeでポインタつかって無駄に高速化をはかります。
ポインタ使うと速くなるのは、配列のバインド チェックが削除されるからです。


まずは普通に書く。(これが一番高速っぽいです)

        unsafe static string Reverse(string s)
        {
            fixed (char* pc = s)
            {
                string newtext = new string(pc);
                fixed (char* pChar = newtext)
                {
                    char swapChar;
                    int length = s.Length - 1;
                    for (int i = 0, j = length; i < j; i++, j--)
                    {
                        swapChar = pChar[i];
                        pChar[i] = pChar[j];
                        pChar[j] = swapChar;
                    }
                }
                return newtext;
            }
        }


せっかくだから、俺はポインタでスワップするゼ

        unsafe static string Reverse(string s)
        {
            fixed (char* pc = s)
            {
                string newtext = new string(pc);
                fixed (char* pChar = newtext)
                {
                    char swapChar;
                    int length = s.Length - 1;
                    char* pStart = pChar;
                    char* pEnd = pChar + length;

                    while (pStart < pEnd)
                    {
                        swapChar = *pStart;
                        *pStart = *pEnd;
                        *pEnd = swapChar;

                        pStart++;
                        pEnd--;
                    }
                } 
                return newtext;
            }
        }


unsafeでもやっぱりXORでモテたい人のリバース

        unsafe static string Reverse(string s)
        {
            fixed (char* pc = s)
            {
                string newtext = new string(pc);
                fixed (char* pChar = newtext)
                {
                    int length = s.Length - 1;
                    for (int i = 0, j = length; i < j; i++, j--)
                    {
                        pChar[i] ^= pChar[j];
                        pChar[j] ^= pChar[i];
                        pChar[i] ^= pChar[j];
                    }
                } 
                return newtext;
            }
        } 


「ワシのリバースは108式まであるぞ!」
という方がいらっしゃいましたら、ぜひ教えて頂ければ幸いです。
関係ないけど、ラムダ式の中でもunsafeって書けるんですね。今日初めて書きました。