LoginSignup
1
2

More than 5 years have passed since last update.

writeln()に死す

Last updated at Posted at 2015-07-25
  • 以下のコードは、dmd2.067.1で動作を確認しました。
  • D言語を使っていて気づいた、他愛のないことを書いています。
  • まあたらしい内容はありません、ご注意ください

配列の全要素を表示する(ループ)

配列の中身を表示するのを愚直にやると、
ブラケットで囲って、ループで回して、要素をカンマで区切って、
こんな感じでやると思います。

D
import std.stdio;

// 一次元配列の表示関数
void writeArray(int[] arr)
{
    "[".write;
    foreach (elem; arr[0 .. $ - 1])
    {
        elem.write;
        ", ".write;
    }
    arr[$ - 1].write;
    "]".write;
}

// 二次元配列の表示関数
void writeMatrix(int[][] mat)
{
    "[".write;
    foreach (elem; mat[0 .. $ - 1])
    {
        elem.writeArray;
        ", ".write;
    }
    mat[$ - 1].writeArray;
    "]".write;
}

void main()
{
    auto arr = [0, 1, 2, 3, 4];
    auto mat = [[0, 1], [2, 3], [4, 5]];
    arr.writeArray;
    writeln("");
    mat.writeMatrix;
}
Output
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]

テンプレート化(再帰+ループ)

ここでwriteArraywriteMatrixは、構造がほとんど同じなので
テンプレート関数を使って一つにまとめます。
std.traitsisArrayテンプレートを使用して、
配列かそうでないかの場合分けをしています。

D
import std.stdio, std.traits;

// 多次元配列の表示関数
void writeMatrix(M)(M mat)
{
    void writeArray(A)(A arr)
    {
        static if (isArray!A)
        {
            "[".write;
            foreach (elem; arr[0 .. $ - 1])
            {
                writeArray(elem);
                ", ".write;
            }
            writeArray(arr[$ - 1]);
            "]".write;
        }
        else
        {
            arr.write;
        }
    }
    writeArray(mat);
    writeln("");
}

void main()
{
    auto      arr  = [0, 1, 2, 3, 4];
    int[2][3] mats = [[0, 1], [2, 3], [4, 5]];
    auto      matd = [[0, 1], [2, 3], [4, 5]];
    arr.writeMatrix;
    mats.writeMatrix;
    matd.writeMatrix;
}
Output
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]
[[0, 1], [2, 3], [4, 5]]

次元を下げながら再帰をしていき、配列ではなくなったら
値を表示するという処理の流れです。
テンプレート化の効能として、多次元、及び静的配列にも対応することができました。
(ネスト関数をUFCSできないのが悔しいですね。。。)

文字列操作バージョン

構造はずいぶんスッキリしましたが、
都度、標準出力にwriteしているのはイケてない気もします。
表示する内容の文字列をあらかじめ作成しておき、
最後にwritelnするように変更してみましょう。

D
import std.stdio, std.traits, std.conv;

void writeMatrix(M)(M mat)
{
    string result;
    void inner(A)(A arr)
    {
        static if (isArray!A)
        {
            result ~= "[";
            foreach (elem; arr[0 .. $ - 1])
            {
                inner(elem);
                result ~= ", ";
            }
            inner(arr[$ - 1]);
            result ~= "]";
        }
        else
        {
            result ~= arr.to!string;
        }
    }
    inner(mat);
    result.writeln;
}

やったか?!

std.string.joinで、ブラケットとカンマ区切りの加工を行い、
std.string.mapで、ループ処理をすればもっと簡単になりそうです。

D
import std.stdio, std.traits, std.conv, std.string, std.algorithm;

void writeMatrix(M)(M mat)
{
    string inner(A)(A arr)
    {
        static if (isArray!A)
            return ["[", "]"].join( arr.dup.map!( elem => inner(elem) ).join(", ") );
        else
            return arr.to!string;
    }
    inner(mat).writeln;
}

dupがないと静的配列の場合にエラーになるようです。
なにはともあれ、よかったよかった。

あ、手がすべっtt

「あっ」

D
import std.stdio;

void main()
{
    auto      arr  = [0, 1, 2, 3, 4];
    int[2][3] mats = [[0, 1], [2, 3], [4, 5]];
    auto      matd = [[0, 1], [2, 3], [4, 5]];

    arr.writeln;
    mats.writeln;
    matd.writeln;
}
Console
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]
[[0, 1], [2, 3], [4, 5]]

「・・・」

「・・・」

「(普通にwritelnで出るじゃん・・・)」

※↓2015.07.27追記
コメントでwriteflnを使う方法を教えて頂きました。

D
auto      matd = [[0, 1], [2, 3], [4, 5]];
writefln("%(%(%d %)\n%)", matd);
Output
0 1
2 3
4 5

「(writefln、かしこい・・・!)」

結論

D言語のwriteln関数は、多次元配列も表示してくれます。
とても便利! 皆さんどんどん使いましょう!

次回、「to!(int[])に死す」。デュエルスタンバイ!(続きません)

1
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2