2 番目のフィールドでのソート
2 列目で、並べ替えをするには?に 2 番目のフィールドでのソートについて質問されていますが、awk の場合には決して簡単なことではありません。
最初に nawk のような sort 関数を持っていないものを awk で作成したものを示します。 さらにここではマージソートを使っていますが、そのマージソートの中の比較している部分を直接変更したものを載せます。
#! /usr/bin/gawk -f
# 2nd_field_sort.awk
{
line[NR] = $0;
}
END {
merge_sort(line, 1, NR, 2);
for (i = 1; i <= NR; i++) {
print line[i];
}
}
#---------------------------------------------------------------------
# function for recursive merge sort
function merge_sort(arr, a, b, key, k) {
if (a < b) {
k = int((a + b) / 2);
merge_sort(arr, a, k, key);
merge_sort(arr, k + 1, b, key);
merge(arr, a, k, b, key);
}
}
#---------------------------------------------------------------------
# function for merge
function merge(arr, a, k, b, key, i, j, p, c) {
j = i = a;
p = k + 1;
while (a <= k && p <= b) {
split(arr[a], arr_key1);
split(arr[p], arr_key2);
if (arr_key1[key] <= arr_key2[key]) {
c[i++] = arr[a++];
} else {
c[i++] = arr[p++];
}
}
while (a <= k) {
c[i++] = arr[a++];
}
while (p <= b) {
c[i++] = arr[p++];
}
while (j <= b) {
arr[j] = c[j];
j++;
}
}
さて、これを実行してみます。
$ cat sample.txt AA 55 AA AA BB 44 BB BB CC 33 CC CC DD 22 DD DD EE 11 EE EE $ gawk -f 2nd_field_sort.awk sample.txt EE 11 EE EE DD 22 DD DD CC 33 CC CC BB 44 BB BB AA 55 AA AA
確かに要望どおりにソートされているようです。 自分で sort 関数を全て記述している分、自由度は非常に高いのですが、マージソートを間違えることなく何も見ずに記述するのは大変です。
そこで gawk の asort() 関数を使って簡略化してみましょう。 ただし、asort() 関数にはどの項目をキーとしてソートするかというようなきめ細かな設定ができません。 そこで、asort() に渡す配列に小細工をしてやります。
#! /usr/bin/gawk -f
# 2nd_field_sort2.awk
{
line[NR] = $2 "\t" $0;
}
END {
asort(line);
for (i = 1; i <= NR; i++) {
print substr(line[i], index(line[i], "\t") + 1);
}
}
つまりソートのキーに相当する部分を先頭に持ってきて、対象文字列で使われていない文字を区切りにしておいて、最後に分割しています。 ここでは TAB にしていますが、SUBSEP などのようが良いかもしれません。 実際に実行してみます。
$ cat sample.txt AA 55 AA AA BB 44 BB BB CC 33 CC CC DD 22 DD DD EE 11 EE EE $ gawk -f 2nd_field_sort.awk sample.txt EE 11 EE EE DD 22 DD DD CC 33 CC CC BB 44 BB BB AA 55 AA AA


