[1] 配列のスライス
配列は、その一部分を取り出して、別の配列として扱うことが出来ます。これは、スライスと呼ばれる演算です。スライスの結果は、動的配列型になります。例えば、a[3]~a[7]のスライスを取り出したい場合、次のように記述します。
a[3..8];
a[3..7]ではないことに注意してください。(最後の要素a[8]は含まれない。)
import std.stdio;
void main(){
int a[15] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
write("a[] = [");
foreach(c;a){
writef("%d,",c);
}
writeln("]");
int b[] = a[3..8]; //スライス演算
write("b[] = [");
foreach(c;b){
writef("%d,",c);
}
writeln("]");
}
a[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,]
b[] = [4,5,6,7,8,]
ちなみに、配列aと配列bは、同じ領域を共有します。つまり、スライス演算はコピーを作らないのです。それと、配列の全要素をスライスするには、a[]と記述します。だから、次の二つは同じ意味を持ちます。
a[0..a.length];
a[]
► スポイラーを表示
► スポイラーを表示
配列スライスが代入式の左辺値として使われた場合、スライスに対する代入演算として扱われます。右辺値が要素型の値である場合、スライス全体にその値が代入されます。
import std.stdio;
void main(){
int a[15] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
write("a[] = [");
foreach(c;a){
writef("%d,",c);
}
writeln("]");
a[3..8] = 32; //ここでスライスに代入している。
write("a[] = [");
foreach(c;a){
writef("%d,",c);
}
writeln("]");
}
a[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,]
a[] = [1,2,3,32,32,32,32,32,9,10,11,12,13,14,15,]
このように、a[3]~a[7]の要素に対して、32という値が代入されているわけです。もちろん、配列全体に代入したい場合、a[]=32; のように記述すればいいのです。
► スポイラーを表示
import std.stdio;
void main(){
int a[15] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
int b[15];
write("a[] = [");
foreach(c;a){
writef("%d,",c);
}
writeln("]");
b[] = a; //aの全要素を 配列bにコピーする
write("b[] = [");
foreach(c;b){
writef("%d,",c);
}
writeln("]");
b[2..5] = a[6..9]; //b[2..5]に、a[6..9]をコピーする。
write("b[] = [");
foreach(c;b){
writef("%d,",c);
}
writeln("]");
}
a[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,]
b[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,]
b[] = [1,2,7,8,9,6,7,8,9,10,11,12,13,14,15,]
これらの演算は、並列命令としてコンパイルされる場合がありますから、要素番号の順にコピーされるという仮定は出来ません。それを保証したい場合は、残念ながら、forループを使うほかにないでしょう。
[3] 配列の連結
要素型が同じ2つの配列は連結することが出来ます。連結する為には、~演算子、もしくは~=演算子を用います。~演算子を用いた場合、何があろうと、必ず新しい配列オブジェクトが生成されます。~=演算子を用いた場合、左辺の配列オブジェクトが、新しいバッファを確保することなく連結できるときは、新しい配列オブジェクトを生成することはありません。
当然ですが、~演算子の結果は、元の配列と同じ要素型の動的配列型になります。
import std.stdio;
void main(){
int[]a = [1,2,3,4,5,6,7,8,9,10]; //動的配列
int[5]b = [11,12,13,14,15]; //静的配列
auto d = a ~ b; //配列を連結する。
//これは等しいよね?
writefln("%s ? %s",(d == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]).stringof,d == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
a ~= b; //aにbを追加する。
write("a[] = [");
foreach(c;a){
writef("%d,",c);
}
writeln("]");
writefln("%s ? %s",(a == d).stringof,a == d);
}
d == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] ? true
a[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,]
a == d ? true
書き忘れていましたが、D言語では==演算子や!=演算子で、配列が同じかどうかを判定することが出来ます。また、2つの動的配列型の変数a,bが同じ配列オブジェクトを指しているかを判定するには、中置二項演算子isが使えます。さらに、
!(a is b)
という式は、!=と同じような要領で、!is二項演算子を用いて、
a !is b
と書き換えることが出来ます。次の例では、bはaのコピーを、cはaそのものを指していることに注意してください。
import std.stdio;
void array_out(int[] array){
write("[");
foreach(c;array){
writef("%d,",c);
}
writeln("]");
}
void main(){
int[]a = [1,2,3,4,5,6,7,8,9,10]; //動的配列
int[]b = a.dup ,c = a;
write("a[] == ");
array_out(a);
write("b[] == ");
array_out(b);
write("c[] == ");
array_out(c);
writefln("%s ? %s",(a == b).stringof,a == b);
writefln("%s ? %s",(a is b).stringof,a is b);
writefln("%s ? %s",(a != c).stringof,a != c);
writefln("%s ? %s",(a is c).stringof,a is c);
writefln("%s ? %s",(b == c).stringof,b == c);
writefln("%s ? %s",(b !is c).stringof,b !is c);
}
a[] == [1,2,3,4,5,6,7,8,9,10,]
b[] == [1,2,3,4,5,6,7,8,9,10,]
c[] == [1,2,3,4,5,6,7,8,9,10,]
a == b ? true
a is b ? false
a != c ? false
a is c ? true
b == c ? true
b !is c ? true
► スポイラーを表示