私はこのようなテキストファイルを持っています:
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になるので、特定の値だけでなく、行番号を比較しながらawkprintについて考えていました。
sort
ファイルを最初の列で数値的に、3番目の列で辞書式に:
sort -s -k1n,1 -k3,3 file
注意: -s
はPOSIX仕様の拡張です
GNU sort for -s
次に @ guest's solution を参照してください。それ以外の場合は、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番目の単語でソートされた配列を出力します。単純なsort
がその仕事をすることができるとき、これはやや上を行くかもしれません。以下は、質問に示されている形式とは異なる入力ファイルを考慮していません。
gawk:
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:
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}'
これがあなたが望んでいた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
_が表示されたら、dump
関数(プログラムの先頭で定義)を呼び出します。 for (arg3 in group)
は、_arg3
_をA
、B
、C
の順に設定します。次に、_arg3
_ = A
の場合、ループfor (line_num in group[arg3])
(つまり、for (line_num in group["A"])
は_line_num
_を_1
_、_3
_、_5
_、_6
_の順で、印刷します。
_1 bob A
1 Kate A
1 bill A
1 Jason A
_
他の_$3
_値についても同様です。他の_$1
_値についても同様です。