다른 열의 최대값을 기준으로 열 값을 수정하도록 텍스트 파일을 처리합니다.

다른 열의 최대값을 기준으로 열 값을 수정하도록 텍스트 파일을 처리합니다.

수정하고 싶은 파일이 있습니다. 동일한 문제가 있는 파일이 100개 있습니다. 입력 파일은 다음과 같습니다

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001
                
sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585
                
sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

위 파일에서 세 번째 열의 "합계"는 조회 테이블이며 최대값은 아래 각 샘플의 행을 초과해서는 안 됩니다.

예를 들어 "sample1"의 최대값은 1000이지만, 세 번째 열의 "week1"과 "week2"의 최대값은 "1001"입니다. 나는 이것이 "week1 및 week2"의 몇 행에서만 발생하며 항상 최대값보다 1만 크다는 것을 발견했습니다. "week1" 및 "week2" 행의 출력은 최대값 "1000"으로 업데이트되어야 합니다. 아래 출력 예

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000
                
sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584
                
sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

어떻게 진행해야 하는지 지침을 제공해 주세요. 저는 배우고 싶은 초보 프로그래머입니다. 당신의 도움을 주셔서 감사합니다

답변1

사용행복하다(이전 Perl_6)

~$ raku -e 'my @a = slurp.split("\n\n", 2);  print @a[0] ~ "\n\n"; 
            my %h;  for @a.[0].lines() { \%h.push: .words.[0,4] }; 
            for @a[1].lines {
                S/^ (\S+)(.* \s)(\S+) $/{"$0$1"}{ %h{$0} < $2 ?? "%h{$0}" !! "$2" }/.put };'   file.txt

Raku는 Perl 계열의 프로그래밍 언어이므로 구문은 틀림없이 "Perl과 유사"합니다. 위에서는 slurp파일을 한꺼번에 메모리에 넣고 2첫 번째 단락 이후에 파일을 여러 부분으로 나눕니다. 이 데이터는 @a배열 에 저장됩니다 . 기준값( )이 포함된 첫 번째 부분은 @a[0]즉시 편집됩니다 print.

%h그런 다음 해시 값을 선언합니다. ...() 를 @a[0]사용하여 for상단 요약 단락을 반복 합니다 lines. 여기서 각 행은 공백으로 구분된 행으로 분할 words되고 첫 번째/다섯 번째 열은 .[0,4]참조 키/값 쌍으로 push해시에 추가됩니다 .%h

파일의 나머지 부분( )은 @a[1]다음을 사용하여 반복됩니다. 이는 블록의 각 줄을 분석/수정할 수 있음을 의미합니다. 수정된 문자열을 반환하기 위해 Raku의 비파괴 대체 관용구를 사용하여 입력을 첫 번째(키) 열, 중간 열 및 마지막(값) 열로 분할합니다.forlinesS///$0$1$2

교체에서는 그대로 {"$0$1"}인쇄합니다. 그러나 마지막 열의 경우 Raku의 삼항 연산자를 사용하여 중괄호 안에 코드를 실행할 수 있습니다.시험 ?? 진짜 !! 잘못된이보다 작으면 %h{$0}( key관련 항목)을 반환하고, 그렇지 않으면 원래 값()을 반환합니다.value$2$2

입력 예:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001

sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585

sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

예제 출력:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000

sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584

sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

마지막으로 중간 데이터 구조를 살펴보는 것이 도움이 되는 경우가 많으므로 %h해시는 다음과 같습니다(used .say for %h.sort;).

sample1 => 1000
sample2 => 5584
sample3 => 8125
sample4 => 59

https://docs.raku.org/syntax/S%2F%2F%2F%20Non-destructive%20replacement
https://docs.raku.org/언어/operators#infix_??_!!
https://docs.raku.org/언어/regexes
https://raku.org

답변2

간단한 Awk 문:

awk -v OFS='\t' '$3 == "total" {maxval[$1] = $5} $1 in maxval && $5 > maxval[$1] {$5 = maxval[$1]} {print}' input.txt

몇 가지 줄 바꿈을 추가했습니다.

awk -v OFS='\t' '
  $3 == "total" {
    maxval[$1] = $5
  }
  $1 in maxval && $5 > maxval[$1] {
    $5 = maxval[$1]
  }
  {print}' input.txt

설명하다:

첫째, 입력 파일의 변수 간격을 기반으로 원본 텍스트에서는 탭으로 구분된 텍스트라고 가정합니다.

기본적으로 Awk는 인접한 탭이나 공백 수에 따라 별도의 필드로 구문 분석합니다. 이 파일에는 괜찮습니다.

그러나 우리는 출력이 깔끔하게 정렬되기를 원하며 기본적으로 일부 필드 값을 변경하면 Awk는 해당 줄의 모든 필드 구분 기호를 단일 공백으로 변환합니다. 따라서 출력 필드 구분 기호(OFS)를 탭과 동일하게 설정하고 -v변수를 설정하는 플래그를 사용합니다.

세 번째 필드가 "total" 문자열인 행의 경우 최대값을 연관 배열(가장 익숙한 프로그래밍 언어에 따라 "해시"라고도 함)에 저장합니다.

행의 첫 번째 필드가 연관 배열에 존재하고 다섯 번째 필드가더 큰해당 키의 최대값으로 배열에 저장된 값보다 현재 행의 다섯 번째 필드를 변경합니다.

그런 다음 수정 여부에 관계없이 현재 줄을 인쇄합니다.

제공된 입력에 대한 출력:

sample1 100A    total   1       1000
sample2 100A    total   1       5584
sample3 100A    total   1       8125
sample4 100A    total   1       59

sample1 .       year    1       1000
sample1 .       week1   20      1000
sample1 .       week2   50      1000

sample2 .       year    1       5584
sample2 .       week1   20      5584
sample2 .       week2   100     5584

sample3 .       year    1       8125
sample3 .       week1   55      8125
sample3 .       week2   100     8125

sample4 .       year    1       59
sample4 .       week1   10      59
sample4 .       week2   8       59

관련 정보