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이고 그 위에 음수 값이 하나도 없기 때문입니다.)

양수든 음수든 가장 높은 값을 원할 경우 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숫자 정렬을 사용하고 있습니다. 좋은 점은 처음 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

관련 정보