根据不同的第一列查找所有列的最大值

根据不同的第一列查找所有列的最大值

我正在使用 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

awk解决方案任何列数(您已经提到过包含 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

该脚本仅使用二维数组 a来存储 2 列中每一列的最大值。对于i第一列的每个值, 将保存在第二列中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 

请注意,上述解决方案对于负值将无法正常工作,或者如果您可以使用0etc,它可能会导致字段的顺序错误,因为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 列项目,第二个列表用于所有第 3 列项目。基本上是这样的:

('1', [ ['10', '4', '40'], ['15', '22', '76']] )

现在,有一个非常好的函数叫做max(),它允许我们获取一个数字列表并从中提取最大的项目。我们所要做的就是迭代每个键,取出所有列表,并对max()它们应用函数。

相关内容