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

列1の38から40の間の列3の最大値を見つける必要があります。

これは単なるサンプルデータセットです。

答え1

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

注:$ 3には正の値はありません。ここで、38 <= $1 <= 40 です。これが出力が空の行になった理由です。 (なぜですか?maxデフォルトは 0 で、その上に負の値が 1 つもないからです。)

正または負のいずれかで最も高い値が必要な場合は、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

「1つの作業のための1つのツール」というUnixの精神の1つの解決策は、行フィルタリングを使用してからソートをawk使用することですsort

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

具体的には、3番目の列を使用して反転(最も大きい値から始まる)と行を表示する-n数値ソートを使用しています。良い点は、最初の3つの値、最小値などに拡張するのが非常に簡単です。-k3-rhead -n 1

答え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スペース区切り文字を読み取って中断して、words38と40の間の列1の値(0インデックス=)を見つけ、grep列3(0インデックス=)の値の固定値からそれを抽出します。.[0]maxNum.[2]

[関心のある読者のための注意:0行を返すように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より小さい)。 Column_3 値を指定する代わりに、上記grepの文を自由に変更して使用することができます(他の答えと同じ)。<=<-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

関連情報