我们如何从第 1 列的一系列值中找到第 3 列的最大值?

我们如何从第 1 列的一系列值中找到第 3 列的最大值?

我在 Ubuntu 机器上有这个数据集:

37.500  0.0000  0.005605
37.750  0.0000  -0.027858
38.000  0.0000  -0.060678
38.250  0.0000  -0.088557
38.500  0.0000  -0.109210
38.750  0.0000  -0.122482
39.000  0.0000  -0.129770
39.250  0.0000  -0.133190
39.500  0.0000  -0.134538
39.750  0.0000  -0.134015
40.000  0.0000  -0.129660
40.250  0.0000  -0.117858
40.500  0.0000  -0.094709
40.750  0.0000  -0.057622
41.000  0.0000  -0.006853

我需要找到第 3 列的最大值,该最大值位于第 1 列的 38 和 40 之间。

这只是一个示例数据集。

答案1

awk '$1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
     END {print out}' input.txt 

注意:$3 没有正值,其中 38 <= $1 <= 40。这就是输出为空行的原因。 (为什么?因为max默认为 0,并且没有一个负值高于该值)。

如果您想要最高值,无论是正值还是负值,请初始化max为小于 $3 中可能的最小值的值。例如-9999

$ awk -v max=-9999 '$1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
                    END {print out}' input.txt 
38.000  0.0000  -0.060678                

或者,使用BEGIN块而不是-v

$ awk 'BEGIN {max=-9999};
       $1 >= 38 && $1 <= 40 && $3 > max {max = $3; out = $0};
       END {print out}' input.txt 
38.000  0.0000  -0.060678                

或者使用 perl,测试 $max 是否未定义,而不是将其初始化为不太可能的值:

$ perl -lane  '
  if ($F[0] >= 38 && $F[0] <= 40 && (!defined($max) || $F[2] > $max)) {
    $max = $F[2]; 
    $out = $_;
  };
  END { print $out }'  input.txt 
38.000  0.0000  -0.060678                

答案2

秉承“一种工具完成一项任务”的 Unix 精神,一种解决方案可能是使用 过滤行awk,然后使用 排序sort

awk '$1>=38 && $1<=40' test.txt  | sort -n -k 3 -r | head -n 1

具体来说,我在这里使用-n数字排序,-k3使用第三列,-r反转(从最大值开始),并head -n 1显示一行。好处是它非常容易扩展到前 3 个值、最小值等。

答案3

sort->sed解决方案。

继续将匹配行放入保持缓冲区 ( /^(3[89]|40\.000)/h),然后最后交换保持+模式缓冲区 ( $x) 和打印模式缓冲区 ( $p)。

$ sort -rk 3n test.txt |sed -nE '/^(3[89]|40\.000)/h;$x;$p'
38.000  0.0000  -0.060678
$

答案4

使用(以前称为 Perl_6)

~$ raku -e 'lines.map(*.words).grep(38 < *.[0] < 40).map(*.[2].Num).max.say;'  file

或(扩展版本):

~$ raku -e 'my @a = lines>>.words; @a.=grep(38 < *.[0] < 40); @a.map(*.[2].Num).max.say;'  file

上面的代码返回单个(最大值)值:-0.088557基于规定的 Column_1 标准。简而言之,lines读入,在空格分隔处断开wordsgrep并查找.[0]38 和 40 之间的第 1 列值(零索引 = ),然后从第 3 列(零索引 = )中的固定值max中提取该值。Num.[2]

[感兴趣的读者请注意:当我更改 Column_1 标准以返回零行时,上面的代码告诉我max获得的 Column_3 值是-Inf]。

阅读评论,似乎OP也希望知道如何返回包含上述值的整行。以下代码完成该任务:

~$ raku -e 'my @a = lines>>.words; @a.=grep(38 < *.[0] < 40); put max(@a, :by(*.[2].Num));'  file
38.250 0.0000 -0.088557

最后,读者可能会注意到此处获得的 Column_3 值与其他发布的答案不同。这是因为当请求针对 Column_1 值时,所使用的 Raku 代码完全按照字面意思获取 OP之间38 和 40(即大于 38 且小于 40)。请放心,将grep上面的语句更改为 use<=而不是<给出 Column_3 值-0.060678(与其他答案相同)。


输入示例:

37.500  0.0000  0.005605
37.750  0.0000  -0.027858
38.000  0.0000  -0.060678
38.250  0.0000  -0.088557
38.500  0.0000  -0.109210
38.750  0.0000  -0.122482
39.000  0.0000  -0.129770
39.250  0.0000  -0.133190
39.500  0.0000  -0.134538
39.750  0.0000  -0.134015
40.000  0.0000  -0.129660
40.250  0.0000  -0.117858
40.500  0.0000  -0.094709
40.750  0.0000  -0.057622
41.000  0.0000  -0.006853

https://raku.org

相关内容