Perlの代替として(7)

delegate

Perlのように、


@a = sort { $a->[1] <=> $b->[1] } @a;

というように、関数を引数に使いたかったのだが、
なぜかDの配列のsortではそれができないのだった。
しかし、sort自作すればそれができる。


delegateは関数みたいなもので、
あまり面白くはないが、こんな例を書いてみた。


import std.cstream;

void main(char[][] arg) {
int b = 3;
bool less(int c) { return c < b; }
print(2, &less); // true
print(4, &less); // false
}

void print(int a, bool delegate(int d) f) {
dout.writefln(f(a));
}

&が要るというのが最初わからなかった。
lessというのがdelegateで、
これをprintという関数の引数にしていて、
もう一つの引数がbより小さいかを出力する。



さて、sortを自作しよう。
クイックソートはともかく、選択ソートなら誰にでも書けるだろう。


void sort(cData [] ary) {
void swap(int i, int k) {
cData tmp = ary[i]; ary[i] = ary[k]; ary[k] = tmp;
}
for(int i = 0; i < ary.length - 1; i++) {
int min = i;
for(int k = i + 1; k < ary.length; k++) {
if(ary[min] > ary[k])
min = k;
}
swap(i, min);
}
}

この比較をdelegateを用いて行う。


void sort(cData [] ary, int delegate(cData, cData) f) {
void swap(int i, int k) {
cData tmp = ary[i]; ary[i] = ary[k]; ary[k] = tmp;
}
for(int i = 0; i < ary.length - 1; i++) {
int min = i;
for(int k = i + 1; k < ary.length; k++) {
if(f(ary[min], ary[k]) > 0)
min = k;
swap(i, min);
}
}
}

fがdelegateで、次のように使う。


int cmp(cData a, cData b) {
return a.rank - b.rank;
}

sort(b, &cmp);

もっとおきらくに、最初のPerlと同じように書きたかったら、
次のように無名delegateを使う。


sort(b, (cData a, cData b) { return a.rank - b.rank; } );

Perlのsortは特殊なので、
それとちがって引数を書かないといけないのはしょうがないだろう。
JavaScriptならこう書かないといけないところだ。


function cData(a, b) {
this.label = a;
this.value = b;
}

var a = [ 3, 11, 2 ];
for(var i in a)
a[i] = new cData(i, a[i]);

a.sort( function(a, b) { return a.value - b.value; } );

まとめると、次のようなコードになった。



import std.cstream;

void main(char[][] arg) {
class cData {
int label, value, rank;
this(int a, int b) {
label = a;
value = b;
}
}

void sort(cData [] ary, int delegate(cData, cData) f) {
void swap(int i, int k) {
cData tmp = ary[i]; ary[i] = ary[k]; ary[k] = tmp;
}
for(int i = 0; i < ary.length - 1; i++) {
int min = i;
for(int k = i + 1; k < ary.length; k++) {
if(f(ary[min], ary[k]) > 0)
min = k;
}
swap(i, min);
}
}

auto a = [ 3, 11, 2 ];
cData [] b;
b.length = a.length;
for(int i = 0; i < a.length; i++) {
b[i] = new cData(i, a[i]);
}

sort(b, (cData a, cData b) { return a.value - b.value; } );

foreach(d; b) {
dout.writefln("%2d. %2d", d.label, d.value);
}
}


2. 2
0. 3
1. 11