각 고유 ID($1)에 대한 레코드의 최대값과 최소값($3)의 차이를 인쇄해야 합니다.
데이터 파일
Id str mt no
101 2 550 1
101 3 540 2
101 3 350 3
101 4 600 4
101 4 700 5
102 1 400 1
102 4 500 2
102 4 350 3
102 3 550 4
103 3 500 1
103 4 300 2
103 3 550 3
산출
Id str mt no diff
101 2 550 1 350
101 3 540 2 350
101 3 350 3 350
101 4 600 4 350
101 4 700 5 350
102 1 400 1 200
102 4 500 2 200
102 4 350 3 200
102 3 550 4 200
103 3 500 1 250
103 4 300 2 250
103 3 550 3 250
답변1
앗다차원 배열을 이용한 방법과분류기능:
awk 'NR==1{ h=$0; } NR>1 { b[NR]=$0;a[$1][length(a[$1])+1]=$3; }
END { print h,"diff";
for (i in a) { asort(a[i]) }
for (k=2;k<=NR;k++) {
split(b[k],sep); max=length(a[sep[1]]);
print b[k],a[sep[1]][max] - a[sep[1]][1]
}
}' file
산출:
Id str mt no diff
101 2 550 1 350
101 3 540 2 350
101 3 350 3 350
101 4 600 4 350
101 4 700 5 350
102 1 400 1 200
102 4 500 2 200
102 4 350 3 200
102 3 550 4 200
103 3 500 1 250
103 4 300 2 250
103 3 550 3 250
답변2
다음은 "교육" 버전입니다.
awk '
NR == 1 {
header=$0
}
NR > 1 {
line[NR]=$0
if($4==1) {
min[$1]=max[$1]=$3
}
else {
if(min[$1]>$3) min[$1]=$3
if(max[$1]<$3) max[$1]=$3
}
}
END {
printf("%s diff\n",header)
for(i=2;i<=NR;i++) {
split(line[i],e)
printf("%s %d\n",line[i],max[e[1]]-min[e[1]])
}
}
' datafile > output
id 열의 순서가 보장된다고 가정하면 훨씬 적은 메모리를 사용하는 더 빠른 버전이 있습니다.
awk 'function f() {for(i in r) printf("%s %d\n",r[i],u-l); delete r}
NR == 1 {printf("%s diff\n",$0)}
NR > 1 {if($4==1) {f(); l=u=$3}
else {if(l>$3)l=$3; if(u<$3)u=$3}
r[$4]=$0 }
END {f()}
' datafile > output
두 스크립트 모두 요청된 출력을 생성하고 POSIX 호환 awk 구현과 함께 사용됩니다. 즉, GNU awk 확장이 필요하지 않습니다(예: asort
.
답변3
perl -lane '
push @A, $_; next if $. == 1; ($a, $b) = @F[0,2];
$b > ($M{$a} // -Inf) and $M{$a} = $b;
$b < ($m{$a} // +Inf) and $m{$a} = $b;
END{$,=$";
print shift @A, q/diff/;
($a) = /\d+/g, print $_, $M{$a} - $m{$a} for @A;
}
' datafile
결과:
Id str mt no diff
101 2 550 1 350
101 3 540 2 350
101 3 350 3 350
101 4 600 4 350
101 4 700 5 350
102 1 400 1 200
102 4 500 2 200
102 4 350 3 200
102 3 550 4 200
103 3 500 1 250
103 4 300 2 250
103 3 550 3 250
답변4
이는 2단계 솔루션입니다.
awk -f runawk first_pass=1 file first_pass=0 file
내용 runawk
은
FNR == 1 && /^Id/{
if (!first_pass) print
next
}
first_pass{
if (!($1 in max)){
min[$1] = max[$1] = $3
next
}
max[$1] = $3 > max[$1]? $3: max[$1]
min[$1] = $3 < min[$1]? $3: min[$1]
}
!(first_pass){
print $1, $2, $3, max[$1] - min[$1]
}