AWK:在一个字段中打印具有最大值的所有行 每个字段,包括具有最大值的相同行

AWK: print ALL rows with MAX value in one field Per the other field including Identical Rows with Max value

提问人:SWK 提问时间:2/9/2023 更新时间:2/10/2023 访问量:175

问:

我正在尝试将每列 2 中具有最高值的行保留在每列 1 中,包括具有最大值的相同行,如下面的所需输出。

数据是

a   55
a   66
a   130
b   88
b   99
b   99
c   110
c   130
c   130

所需输出为

a   130
b   99
b   99
c   130
c   130

我可以从这个网站上找到很好的答案,但并不完全针对当前的问题。

awk '{ max=(max>$2?max:$2); arr[$2]=(arr[$2]?arr[$2] ORS:"")$0 } END{ print arr[max] }' file

生成包含相同行的输出,但最大值来自所有行,而不是每列 1。

a       130
c       130
c       130
awk '$2>max[$1] {max[$1]=$2 ; row[$1]=$0} END{for (i in row) print row[i]}' file

输出包括每列 1 的最大值,但不包括具有最大值的相同行。

a       130
b       99
c       130

你能帮我以所需的方式修剪数据吗?甚至上述所有代码都是从您在本网站的问题和答案中获得的。感谢!!非常感谢您的帮助!!

awk 重复 max 字段

评论

1赞 konsolebox 2/9/2023
为每个重复的条目添加一个计数器,然后打印一个条目计数器。
0赞 SWK 2/9/2023
@konsolebox 我猜你的意思是安德烈在下面提供的方式。欣赏!

答:

3赞 jared_mamrot 2/9/2023 #1

我过去使用过这种方法:

awk 'NR==FNR{if($2 > max[$1]){max[$1]=$2}; next} max[$1] == $2' test.txt test.txt
a   130
b   99
b   99
c   130
c   130

这需要您两次传入同一个文件(即 awk '...'test.txt test.txt),所以它并不理想,但希望它能提供所需的输出和你的实际数据。

评论

1赞 konsolebox 2/9/2023
接下来应该在外块中,第二行可以简化为 .max[$1] == 2
1赞 jared_mamrot 2/9/2023
你是绝对正确的 - 谢谢你的更正 - 我从更复杂的脚本中改编了这个答案。我现在编辑答案。谢谢@konsolebox
0赞 SWK 2/9/2023
@jared_mamrot 衷心感谢它完美地满足了我的需求,并且为及时的回答和后续评论的编辑留下了深刻的印象。谢谢!
2赞 Andre Wildberg 2/9/2023 #2

另一种使用 .第二个循环应该是轻的,只是重复重复的最大值。awk

% awk 'arr[$1] < $2{arr[$1] = $2;                       # get max value
         co[$1]++; if(co[$1] == 1){x++; id[x] = $1}}    # count unique ids
       arr[$1] == $2{n[$1,arr[$1]]++}                   # count repeated max
       END{for(i=1; i<=x; i++){
             for(j=1; j<=n[id[i],arr[id[i]]]; j++){print id[i], arr[id[i]]}}}' file
a 130
b 99
b 99
c 130
c 130

或者,如果顺序无关紧要

% awk 'arr[$1] < $2{arr[$1] = $2}
       arr[$1] == $2{n[$1,arr[$1]]++}
       END{for(i in arr){
             j=0; do{print i, arr[i]; j++} while(j < n[i,arr[i]])}}' file
c 130
c 130
b 99
b 99
a 130

--编辑--

在附加列中打印数据

% awk 'arr[$1] < $2{arr[$1] = $2}
       arr[$1] == $2{n[$1,arr[$1]]++; line[$1,arr[$1],n[$1,arr[$1]]] = $0}
       END{for(i in arr){
             j=0; do{j++; print line[i,arr[i],j]} while(j < n[i,arr[i]])}}' file
c   130 data8
c   130 data9
b   99  data5
b   99  data6
a   130 data3

数据

% cat file
a   55  data1
a   66  data2
a   130 data3
b   88  data4
b   99  data5
b   99  data6
c   110 data7
c   130 data8
c   130 data9

评论

0赞 SWK 2/9/2023
非常感谢您的帮助!它对我有用。当数据具有多个列时,应如何修改打印选项以打印这些行的所有列?谢谢!
1赞 Andre Wildberg 2/9/2023
@SWK我添加了编辑以获取其他列!
1赞 SWK 2/9/2023
它非常适合我的需求,我也感谢您的及时回复!!
2赞 dawg 2/9/2023 #3

这里有一个红宝石可以做到这一点:

ruby -e '
grps=$<.read.split(/\R/).
    group_by{|line| line[/^\S+/]}
# {"a"=>["a   55", "a   66", "a   130"], "b"=>["b   88", "b   99", "b   99"], "c"=>["c   110", "c   130", "c   130"]}

maxes=grps.map{|k,v| v.max_by{|s| s.split[-1].to_f}}
# ["a   130", "b   99", "c   130"]

grps.values.flatten.each{|s| puts s if maxes.include?(s)}
' file  

指纹:

a   130
b   99
b   99
c   130
c   130

评论

0赞 SWK 2/9/2023
我将来可能会寻找使用 ruby 的解决方案,并感谢您的代码和解释。
3赞 Ed Morton 2/10/2023 #4

使用任何 awk:

awk '
    { cnt[$1,$2]++; max[$1]=$2 }
    END { for (key in max) { val=max[key]; for (i=1; i<=cnt[key,val]; i++) print key, val } }
' file
a 130
b 99
b 99
c 130
c 130

评论

3赞 dawg 2/10/2023
这假定按键升序值排序。可固定或预分拣...filemax[$1]=max[$1] < $2 ? $2 : max[$1]
1赞 Ed Morton 2/10/2023
@dawg,对,根据示例输入。如果没有,那么或按照您所说的进行调整。sort file | awk ...
0赞 SWK 2/10/2023
“ 排序文件 |awk ' { cnt[$1,$2]++; max[$1]=$2 } END { for (key in max) { val=max[key]; for (i=1; i<=cnt[key,val]; i++) print key, val } } ' “ 非常适合我的未排序数据!当函数中没有涉及其他列时,我应该如何修改以打印所有列?非常感谢!!
2赞 Ed Morton 2/10/2023
@SWK问一个新问题,因为这是您在这里提出的问题的一个很好的解决方案,但这不是您评论中问题的正确起点。别客气。
0赞 SWK 2/10/2023
@dawg如果你的意思是这样的修改 '' awk '{ cnt[$1,$2]++; max[$1]=max[$1] < $2 ? $2 : max[$1] } END { for (key in max) { val=max[key]; for (i=1; i<=cnt[key,val]; i++) print key, val } }' file “ ,仍然需要排序文件。我可能错了。谢谢!!!