異なる最初の列に基づいてすべての列の最大値を見つける

異なる最初の列に基づいてすべての列の最大値を見つける

私は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配列を使用して、 a2つの列のそれぞれの最大値を格納します。最初の列の各値について、2番目の列の最大値iと3番目の列の最大値が格納されます。a[i][2]ファイル全体を処理した後、各値の最大値を印刷します。ia[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()機能を適用することだけです。

関連情報