項目番号ごとに行を列に並べる

お題 - ときどきの雑記帖 2012 2012年5月(上旬) に記述されていた awkで項目番号ごとに行を列に並べる | OKWave にインスパイヤされて項目番号ごとに行を列に並べてみます。

与えられているサンプルはソートされていますが、ソートされているとは限らず、場合によっては任意の順番で表示したいということですので、以下のような手順で作成します。

  • ファイルから値を読み込みます。
  • X, Y の項目をソートして、一時ファイルに書き出します。
  • ソートされた X, Y を読み込みます。
  • ソートされた順序でテーブルを作成します。

コードとしては以下のようになります。

#! /usr/local/bin/nawk -f
# table.awk

BEGIN {
    #-----------------------------------------------------------------
    input_file = "test.txt";

    # 値の読み込み
    while (getline < input_file > 0) {
        idx_x[$1]   = $1;
        idx_y[$2]   = $2;
        val[$1, $2] = $3;
    }
    close(input_file);

    #-----------------------------------------------------------------
    # X をソート
    tmp_idx_x_file = "tmp_idx_x.txt";
    sort_cmd = "sort > " tmp_idx_x_file;

    for (i in idx_x) {
        print idx_x[i] | sort_cmd;
    }
    close(sort_cmd);

    # Y をソート
    tmp_idx_y_file = "tmp_idx_y.txt";
    sort_cmd = "sort > " tmp_idx_y_file;

    for (i in idx_y) {
        print idx_y[i] | sort_cmd;
    }
    close(sort_cmd);

    #-----------------------------------------------------------------
    # ソートされた X を新しいインデックスとして読み込み
    while (getline < tmp_idx_x_file > 0) {
        ++nr_x;
        sorted_idx_x[nr_x] = $0;
    }
    close(tmp_idx_x_file);

    # ソートされた Y を新しいインデックスとして読み込み
    while (getline < tmp_idx_y_file > 0) {
        ++nr_y;
        sorted_idx_y[nr_y] = $0;
    }
    close(tmp_idx_y_file);

    #-----------------------------------------------------------------
    # 整形したものを出力
    printf("%-8s", "No.");
    for (x = 1; x <= nr_x; x++) {
        printf("%-8s", sorted_idx_x[x]);
    }
    print "";

    for (y = 1; y <= nr_y; y++) {
        printf("%-8s", sorted_idx_y[y]);
        for (x = 1; x <= nr_x; x++) {
            printf("%-8s", val[sorted_idx_x[x], sorted_idx_y[y]]);
        }
        print "";
    }

    #-----------------------------------------------------------------
    # テンポラリファイルの削除
    rm_cmd = "rm -f " tmp_idx_x_file " " tmp_idx_y_file;
    system(rm_cmd);
}

DRY (Don't Repeat Yourself) の思想に合わない記述ですが、気になるようであれば、配列や関数化でも記述できます。

実行してみます。

$ cat test.txt
a   10      1
b   10      2
c   10      3
d   10      4
a   20      5
b   20      6
c   20      7
d   20      8
a   30      9
b   30      0
c   30      1
d   30      2

$ nawk -f table.awk
No.     a       b       c       d
10      1       2       3       4
20      5       6       7       8
30      9       0       1       2

さて、ここではソートされた値を用いていますが、ソートせずに tmp_idx_x_file, tmp_idx_y_file を直接記述すれば、その順番で出力されます。

tag_nawk.png tag_nawk.png tag_nawk.png tag_nawk.png