- 以下のコードは、dmd2.067.1で動作を確認しました。
- 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;
}
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]
テンプレート化(再帰+ループ)
ここでwriteArray
とwriteMatrix
は、構造がほとんど同じなので
テンプレート関数を使って一つにまとめます。
std.traits
のisArray
テンプレートを使用して、
配列かそうでないかの場合分けをしています。
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;
}
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]
[[0, 1], [2, 3], [4, 5]]
次元を下げながら再帰をしていき、配列ではなくなったら
値を表示するという処理の流れです。
テンプレート化の効能として、多次元、及び静的配列にも対応することができました。
(ネスト関数をUFCSできないのが悔しいですね。。。)
文字列操作バージョン
構造はずいぶんスッキリしましたが、
都度、標準出力にwrite
しているのはイケてない気もします。
表示する内容の文字列をあらかじめ作成しておき、
最後にwriteln
するように変更してみましょう。
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
で、ループ処理をすればもっと簡単になりそうです。
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
「あっ」
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;
}
[0, 1, 2, 3, 4]
[[0, 1], [2, 3], [4, 5]]
[[0, 1], [2, 3], [4, 5]]
「・・・」
「・・・」
「(普通にwritelnで出るじゃん・・・)」
※↓2015.07.27追記
コメントでwriteflnを使う方法を教えて頂きました。
auto matd = [[0, 1], [2, 3], [4, 5]];
writefln("%(%(%d %)\n%)", matd);
0 1
2 3
4 5
「(writefln、かしこい・・・!)」
結論
D言語のwriteln
関数は、多次元配列も表示してくれます。
とても便利! 皆さんどんどん使いましょう!