連想配列の値でソート

連想配列は非常に便利ですが、キーを保ったままソートするようなことは得意とはいえません。 連想配列の値でソート (mixi なのでアカウントが必要ですので、アカウントがない場合は mixiの課題丸投げをひたすら解く、Pythonで を見てください) のような場合には困ってしまいます。

いろいろな解法があると思いますが、個人的には一度配列を作り直すという方法を良く用います。 ここでは触れませんが、この方法だと sort コマンドに渡して処理をさせるようなことも可能になります。 一方で、データ構造を崩すわけですから、元に戻す際に注意することが必要です。 ここでは gawk の asort() 関数を有効に使うようにしてみます。

ただし、これがベストな解法というわけではありません。 もっとスマートな方法があるかもしれません。

#! /usr/bin/gawk -f
# key_sort.awk

BEGIN {
    data["e"] = 831;
    data["em"] = 3;
    data["i"] = 191;
    data["p"] = 191;
    data["v"] = 158;
    data["w"] = 386;

    for (key in data) {
        tmp_data[++i] = sprintf("%3d%s%s", data[key], SUBSEP, key);
    }

    num_tmp_data = asort(tmp_data);

    for (i = num_tmp_data; i >= 1; i--) {
        split(tmp_data[i], arr_tmp_data, SUBSEP);
        num = arr_tmp_data[1] + 0;
        key = arr_tmp_data[2];
        print key " => " num;
    }
}

asort() 関数は便利ですが、ソートに用いるキーを指定するようなことはできません。 そこで、SUBSEP のような普段使わない文字を使って区切られた配列を生成しておいて、これを asort() に入れます。 ソート後には、SUBSEP で split して表示させています。 ここでは大きい順ということなので、for ループを逆順で回しています。 実行してみましょう。

$ gawk -f key_sort.awk
e => 831
w => 386
p => 191
i => 191
v => 158
em => 3

取得することができました。

データ構造は言語で後から扱うことが便利なように配慮するべきだと思いますが、実際に作っていくとうまく扱えずに変更を行うようなケースもあるでしょう。 awk には awk に優しいデータ構造とアルゴリズムを選びましょう。

tag_gawk.pngtag_gawk.png