sort(2)
クラスのオブジェクトのソートは次のようにする。
import std.stream;
import std.cstream;
import std.string;void main(char[][] arg) {
class cData {
int rank, value;
this(int a, int b) {
rank = a;
value = b;
}
int opCmp(Object o) {
cData d = cast(cData)o;
return rank - d.rank;
}
}
auto a = [ 3, 11, 2 ];
cData [] b;
b.length = a.length;
for(int i = 0; i < a.length; i++) {
b[i] = new cData(a[i], a[i]);
}
b.sort;
foreach(d; b) {
dout.writefln("%2d %2d", d.rank, d.value);
}
}
出力:
2 2
3 3
11 11
クラスにopCmpという関数が定義されていないといけない。
ふつうに大小を正・負・0で返せばよい。
ただし、引数はObjectクラスで、上のようにキャストして使う。
opCmpが定義されていれば、比較演算子が使える。
auto a = [ 2, 11, 3 ];
cData [] b;
b.length = a.length;
for(int i = 0; i < a.length; i++) {
b[i] = new cData(a[i], a[i]);
}
dout.writefln(b[0] > b[2]); // false
使えるのは >,>=,<=,< で、
== を使えるようにするには、同様にopEqualsを定義する。
int opEquals(Object o) {
cData d = cast(cData)o;
return rank == d.rank;
}
Cのライブラリのqsortを使えば比較関数を引数に取れるようだが、
よくわからなかった。
実は、ソートについて考えるときに、
与えられた配列に対して順位をつけるという例を考えていた。
すなわち、
3
11
2
という配列があれば、
2. 3
3. 11
1. 2
というものだった。
Perlでは、こんなカンジ。
@a = ( 3, 11, 2 );
@a = map { [ $_, $a[$_] ] } 0..$#a; # ラベルをつける
@a = sort { $a->[1] <=> $b->[1] } @a; # 値でソート
@a = map { [ $_ + 1, @{$a[$_]} ] } 0..$#a; # 順位をつける
@a = sort { $a->[1] <=> $b->[1] } @a; # ラベルでソート
for(@a) {
print "$_->[0]. $_->[2]\n"; # 順位と値を出力
}
だが、Dではスマートな方法を思いつかなかった。