特定の列で同じフィールド値を持つ行グループのソート

特定の列で同じフィールド値を持つ行グループのソート

次のテキストファイルがあります。

1 bob A
1 jim B
1 Kate A
1 Nancy C
1 bill A
1 Jason A
2 James B
2 fill B
2 cake C
2 lucky C
2 Lucy A
2 lily B

各グループ1と2のデータを3列で並べ替えるにはどうすればよいですか?出力は次のようになります。

1 bob A
1 Kate A
1 bill A
1 Jason A
1 jim B
1 Nancy C
2 Lucy A
2 James B
2 fill B
2 lily B
2 cake C
2 lucky C

Kate入力順に表示されるため、出力の前に表示されます。bill

列1には1、2から2000までの非常に大きな値があるため、行数を比較するときは単に特定の値と同じだけでなく、awk printも考慮します。

答え1

sortファイルは、最初の列に基づいて数値順に、3番目の列に基づいてアルファベット順にソートされます。

sort -s -k1n,1 -k3,3 file

注:-sPOSIX仕様の拡張です。

答え2

GNUソートがある場合は、-s以下を参照してください。@guestのソリューション、そうでない場合はcat + sort + cutを使用してください。

$ cat -n file | sort -k2,2n -k4,4 -k1,1n | cut -f2-
1 bob A
1 Kate A
1 bill A
1 Jason A
1 jim B
1 Nancy C
2 Lucy A
2 James B
2 fill B
2 lily B
2 cake C
2 lucky C

答え3

配列の各行を収集します。行の最初の単語が前の最初の単語と異なる場合は、3番目の単語でソートされた配列を印刷します。簡単な作業で作業を行うsortと、これは少し過剰になる可能性があります。以下は、質問に示されているものとは異なる形式の入力ファイルを考慮しません。

愚かな:

BEGIN {ors=ORS; ORS=""; PROCINFO["sorted_in"]="@ind_str_asc"}

$1!=r {
    output()
    delete a
    r=$1
}
{
    a[$3]=a[$3] $0 ors
}

END {
    output()
}

function output() {
    for (i in a)
        print a[i]
}

Python:

import fileinput, operator
r=''; a=[]
def out():
    for p in sorted(a,key=operator.itemgetter(2)):
        print(' '.join(p))

for line in fileinput.input():
    x = line.rstrip().split()
    if r!=x[0]:
        r=x[0]
        if a:
            out()
            del a[:]
    a.append(x)
out()

真珠:

perl -lae 'sub out {foreach(sort keys %a) {print $a{$_}}} BEGIN {$ors=$\;$\=""}
    if ($F[0] ne $r) {$r=$F[0]; out; %a=()}
    $a{$F[2]}=$a{$F[2]}.$_.$ors; END{out}'

答え4

これがawkあなたが望む解決策です。 (特にgawk [GNU  awk]; POSIXでは機能しません  awk。)

awk '
        function dump() {
                PROCINFO["sorted_in"] = "@ind_str_asc"
                for (arg3 in group) {
                        PROCINFO["sorted_in"] = "@ind_num_asc"
                        for (line_num in group[arg3]) {
                                print group[arg3][line_num]
                        }
                        PROCINFO["sorted_in"] = "@ind_str_asc"
                }
        }
        {
                if ($1 != saved_arg1) {
                        dump()
                        delete group
                        saved_arg1 = $1
                }
                group[$3][NR] = $0
        }
        END {
                dump()
        }
    '

主な作業は途中から始まります。各行について、$1その値が最近見た値と異なる場合は、新しいグループに入ることを意味します。古いデータセットをダンプし(つまり、出力に書き込む)、以前に保存されたデータセットを削除し、新しい$1値を記憶します。

どちらの場合も、現在の行が配列groupに追加されます。これは$3、値とNR (行番号)で索引付けされた2次元配列です。たとえば、サンプル入力の最初の6行について、次のようになります。

group["A"][1] = "1 bob A"
group["B"][2] = "1 jim B"
group["A"][3] = "1 Kate A"
group["C"][4] = "1 Nancy C"
group["A"][5] = "1 bill A"
group["A"][6] = "1 Jason A"

行7に$1 =が表示されている場合は、関数(プログラムの上部に定義されています)を2呼び出します。 、dumpfor (arg3 in group)設定arg3してください。その後、for =、ループ(つまり、、、および順次に設定されます。したがって、次のように印刷します。ABCarg3Afor (line_num in group[arg3])for (line_num in group["A"])line_num1356

1 bob A
1 Kate A
1 bill A
1 Jason A

他の値はこのように推論されます$3。他の値はこのように推論されます$1

関連情報