Help us understand the problem. What is going on with this article?

writeln()に死す

More than 5 years have passed since last update.
  • 以下のコードは、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[])に死す」。デュエルスタンバイ!(続きません)

nak2yoshi
D言語勉強中/ネコが好き
https://twitter.com/nak2yoshi
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした