2015年02月08日

C#で与えられた文字列でピラミッド

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その68

「ピラミッドを作る」の続編です。 与えられた文字列を使って下の例のようなピラミッドを書いてください。 頂点は与えられた文字列の最後の一文字、 底辺は与えられた文字列の各文字の間に空白が入ったものになります。
>>> pyramid("hoge")
   e  
  g e 
 o g e
h o g e



>>> pyramid("abracadabra")
          a         
         r a        
        b r a       
       a b r a      
      d a b r a     
     a d a b r a    
    c a d a b r a   
   a c a d a b r a  
  r a c a d a b r a 
 b r a c a d a b r a
a b r a c a d a b r a


※ ごめんなさい、出題者がわかりません。

いろいろな書き方が考えられますね。 最初に書いたバージョンはこれ。
static void Pyramid1(string s) {
    int length = s.Length;
    for (int n = 0; n < length; n++) {
        // 左側の空白を表示
        int spCount = length - n - 1;
        Console.Write(new string(' ', spCount));
        // 右側の文字部分を表示
        var ls = s.Skip(spCount);
        foreach (var c in ls)
            Console.Write(c + " ");
        Console.WriteLine();
    }
}
メソッドの中で出力も行っているのが気に入らなかったので、 文字列の組み立てだけを行うメソッドにして見ました。 ついでに、上記メソッドの最後の foreach文の箇所をLINQ to Ojectを使って 書き直してみました。
static IEnumerable<string> Pyramid2(string s) {
    int length = s.Length;
    for (int n = 0; n < length; n++) {
        // 左側の空白の数
        int spCount = length - n - 1;
        // 右側の文字部分を表示
        yield return s.Skip(spCount)
                      .Aggregate(new string(' ', spCount), (x, c) => x + c + " ");
    }
}
出力までやるには、以下のようなコードを書きます。
        static void Main(string[] args) {
            Pyramid2("abracadabra").ToList().ForEach(Console.WriteLine);
            Console.ReadLine();
        }
ここまで書いたのだから、全部 LINQ使っちゃえ、って書いたのが次に示すコード。 ここまでやると、黒魔術的なにおいがしてきます。
static IEnumerable<string> Pyramid3(string s) {
    return Enumerable.Range(0, s.Length).Reverse()
            .Select(
                n => s.Skip(n).Aggregate(new string(' ', n), (x, c) => x + c + " ")               
            );
}
再帰処理だと、どんな感じになるのかなと想い、書いてみたのが次のコード。 これが一番すっきりしている感じがします。
static string Pyramid(string s) {
    return PyramidRec(s.Length - 1, s);
}

// indexは、abracadabra の場合は、10,9,8,7,... と変化していく。
// 左側に詰める空白の数
static string PyramidRec(int index, string s) {
    if (index < 0)
        return "";
    string line = new string(' ', index) +
                  s.Skip(index).Aggregate("", (x, c) => x + c + " ");
    return line + Environment.NewLine + PyramidRec(index - 1, s);
}
再帰処理でのyield return って煩雑なので、戻り値を string にして、 改行込みの結果を返すようにしています。 もちろん、コンソールに出力するには、以下のように書けばOK.
Console.WriteLine(Pyramid("abracadabra"));


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/52407159