私はUbuntuを使用しており、次のような入力ファイルがあります。
ifile.dat
1 10 15
3 34 20
1 4 22
3 32 33
5 3 46
2 2 98
4 20 100
3 13 23
4 50 65
1 40 76
2 20 22
どうやってこれを達成できますか?
ofile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
私の言葉は、最初の列を比較して各列の最大値を取得することです。ありがとうございます。
私が試したことは次のとおりです(13列のサンプルファイルから)。しかし、最も高い価値はそれほど現れません。
cat input.txt | sort -k1,1 -k2,2nr -k3,3nr -k4,4nr -k5,5nr -k6,6nr -k7,7nr -k8,8nr -k9,9nr -k10,10nr -nrk11,11 -nrk12,12 -nrk13,13 | sort -k1,1 -u
動作しません。役に立つ人が以下でこの問題を解決するのを手伝ってください。しかし、MacやUbuntuのgawkでは実行できず、以下のエラーが表示されます。
awk 'BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if (a[$1][i]<$i){a[$1][i]=$i}} END{n=asorti(a, asorted); for(col1 in asorted){print col1, a[col1][2], a[col1][3]}}' input.txt
エラーは次のとおりです。
awk: syntax error at source line 1
context is
BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if >>> (a[$1][ <<<
awk: illegal statement at source line 1
awk: illegal statement at source line 1
BEGINステートメントを削除してforループを試してみましたが、運がありませんでした。ありがとうございます。
PS:stackoverflowからこの回答を得ました。ここがUnix / Linuxフォーラムであるため、ここに記事を投稿することになりました。
答え1
GNUデータの混合次のような場合は大丈夫です。
$ datamash -sW groupby 1 max 2,3 < ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
より多くの列を処理するには、次のように指定できます。範囲例えば
datamash -sW groupby 1 max 2-13 < ifile.dat
答え2
アッ解決策どの列数(すでに述べた13列のサンプルファイル):
拡張されたサンプルファイルがあるとします。
1 10 15 10 99
3 34 20 20 111
1 4 22 22 33
3 32 33 12 5
5 3 46 44 9
2 2 98 55 55
4 20 100 11 33
3 13 23 77 23
4 50 65 33 66
1 40 76 78 16
2 20 22 98 93
awk '{ for(i=2;i<=NF;i++) { if (!($1 in a) || $i > a[$1][i]) a[$1][i]=$i }}
END{ r=""; for(i in a) { r=i; for(j in a[i]) r=r OFS a[i][j]; print r }
}' OFS='\t' file
出力:
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
答え3
これはawkの方法です。
$ awk '{
if($2 > a[$1][2]){
a[$1][2] = $2
}
if($3 > a[$1][3]){
a[$1][3] = $3
}
}
END{
for(i in a){
printf "%s ", i;
for(c=1; c<=maxFields; c++){
if(c in a[i]){
printf "%s ",a[i][c]
}
}
print ""
}' ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
スクリプトは単に2D配列を使用して、 a
2つの列のそれぞれの最大値を格納します。最初の列の各値について、2番目の列の最大値i
と3番目の列の最大値が格納されます。a[i][2]
ファイル全体を処理した後、各値の最大値を印刷します。i
a[i][3]
i
列が3つ以上の場合は、次のものを使用できます。
awk '{
for(c=2; c<=NF; c++){
if($c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s: ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
上記の解決策は、負の値に対して正しく機能しないか、または使用可能な場合、配列が必ずしも順番に移動されないため、0
フィールドの順序が正しくない可能性がありますawk
。より強力なアプローチは次のとおりです。
awk '{
for(c=2; c<=NF; c++){
if(!(c in a) || $c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
答え4
Python 3スクリプト
#!/usr/bin/env python3
import sys
from collections import OrderedDict as od
# read data in the file first, create data dictionary of column lists
data = od()
with open(sys.argv[1]) as f:
for line in f:
columns = line.strip().split()
how_many = len(columns)-1
if columns[0] not in data.keys():
data[ columns[0] ] = [ [] for i in range(how_many) ]
for index in range(how_many):
data[ columns[0] ][index].append( int(columns[index+1]) )
# post process all the created lists of lists by applying max() on each
for item in sorted(data.keys()):
print(item,end=" ")
for array in data[item]:
print(max(array),end=" ")
print("")
テストの実行
OPによって提供される入力の例:
$ ./columns_max.py input.txt
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
Roman Perekhrestの答えには拡張例があります。
$ ./columns_max.py input.txt
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
動作原理:
基本的なアイデアは、最初の列項目として辞書を作成することです。したがって、辞書には1、2、3、4、および5キーがあります。辞書項目の各対応する値はリストのリストであり、各サブリストは列に対応します。したがって、キー1の場合、2つのリストを含むリストがあります。 1 つ目はすべての列 2 項目のもので、2 番目はすべての列 3 項目のものです。基本的には次のようになります。
('1', [ ['10', '4', '40'], ['15', '22', '76']] )
これで本当に素晴らしい関数があります。max()
これにより、数字のリストを取得してその中で最大の項目を抽出できます。私たちがしなければならないのは、各キーを繰り返してすべてのリストを取得し、ここにmax()
機能を適用することだけです。