저는 Ubuntu를 사용하고 있으며 다음과 같은 입력 파일이 있습니다.
ifile.dat
1 10 15
3 34 20
1 4 22
3 32 33
5 3 46
2 2 98
4 20 100
3 13 23
4 50 65
1 40 76
2 20 22
어떻게 이를 달성할 수 있나요?
ofile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
내 말은 첫 번째 열을 비교하여 각 열의 최대 값을 얻는 것입니다. 감사해요.
내가 시도한 내용은 다음과 같습니다(13개 열이 있는 샘플 파일에서). 하지만 가장 높은 가치는 그렇게 나타나지 않습니다.
cat input.txt | sort -k1,1 -k2,2nr -k3,3nr -k4,4nr -k5,5nr -k6,6nr -k7,7nr -k8,8nr -k9,9nr -k10,10nr -nrk11,11 -nrk12,12 -nrk13,13 | sort -k1,1 -u
작동하지 않습니다. 도움이 되는 사람이 아래에서 이 문제를 해결하도록 도와주려고 합니다. 하지만 Mac이나 우분투의 gawk에서는 실행할 수 없으며 아래 오류가 표시됩니다.
awk 'BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if (a[$1][i]<$i){a[$1][i]=$i}} END{n=asorti(a, asorted); for(col1 in asorted){print col1, a[col1][2], a[col1][3]}}' input.txt
오류는 다음과 같습니다
awk: syntax error at source line 1
context is
BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"} {for(i=2;i<=NF;++i) if >>> (a[$1][ <<<
awk: illegal statement at source line 1
awk: illegal statement at source line 1
BEGIN 문을 제거하고 for 루프를 사용해 보았지만 운이 없었습니다. 감사해요.
추신: stackoverflow에서 이 답변을 얻었습니다. 여기가 유닉스/리눅스 포럼이기 때문에 여기에 글을 게시하게 되었습니다.
답변1
GNU 데이터 혼합다음과 같은 경우에는 괜찮습니다.
$ datamash -sW groupby 1 max 2,3 < ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
더 많은 수의 열을 처리하려면 다음을 지정할 수 있습니다.범위예를 들어
datamash -sW groupby 1 max 2-13 < ifile.dat
답변2
앗해결책어느열 수(이미 언급한13개 열이 포함된 샘플 파일):
확장된 예제 파일이 있다고 가정합니다.
1 10 15 10 99
3 34 20 20 111
1 4 22 22 33
3 32 33 12 5
5 3 46 44 9
2 2 98 55 55
4 20 100 11 33
3 13 23 77 23
4 50 65 33 66
1 40 76 78 16
2 20 22 98 93
awk '{ for(i=2;i<=NF;i++) { if (!($1 in a) || $i > a[$1][i]) a[$1][i]=$i }}
END{ r=""; for(i in a) { r=i; for(j in a[i]) r=r OFS a[i][j]; print r }
}' OFS='\t' file
산출:
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
답변3
이것은 awk의 방법입니다.
$ awk '{
if($2 > a[$1][2]){
a[$1][2] = $2
}
if($3 > a[$1][3]){
a[$1][3] = $3
}
}
END{
for(i in a){
printf "%s ", i;
for(c=1; c<=maxFields; c++){
if(c in a[i]){
printf "%s ",a[i][c]
}
}
print ""
}' ifile.dat
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
스크립트는 단순히 2D 배열을 사용하여 a
2개 열 각각의 최대값을 저장합니다. 첫 번째 열의 각 값 에 대해 두 번째 열의 최대값 i
과 세 번째 열의 최대값이 저장됩니다 . a[i][2]
전체 파일을 처리한 후 각 값의 최대값을 인쇄합니다.i
a[i][3]
i
열이 3개 이상인 경우 다음을 사용할 수 있습니다.
awk '{
for(c=2; c<=NF; c++){
if($c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s: ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
위의 솔루션은 음수 값에 대해 제대로 작동하지 않거나 등을 사용할 수 있는 경우 배열이 반드시 순서대로 탐색되지 않으므로 0
필드 순서가 잘못될 수 있습니다 awk
. 보다 강력한 접근 방식은 다음과 같습니다.
awk '{
for(c=2; c<=NF; c++){
if(!(c in a) || $c > a[$1][c]){
a[$1][c] = $c;
}
}
}
END{
for(i in a){
printf "%s ", i;
for(c in a[i]){
printf "%s ",a[i][c]
}
print ""
}
}' ifile.dat
답변4
파이썬 3 스크립트
#!/usr/bin/env python3
import sys
from collections import OrderedDict as od
# read data in the file first, create data dictionary of column lists
data = od()
with open(sys.argv[1]) as f:
for line in f:
columns = line.strip().split()
how_many = len(columns)-1
if columns[0] not in data.keys():
data[ columns[0] ] = [ [] for i in range(how_many) ]
for index in range(how_many):
data[ columns[0] ][index].append( int(columns[index+1]) )
# post process all the created lists of lists by applying max() on each
for item in sorted(data.keys()):
print(item,end=" ")
for array in data[item]:
print(max(array),end=" ")
print("")
테스트 실행
OP에서 제공하는 입력의 예:
$ ./columns_max.py input.txt
1 40 76
2 20 98
3 34 33
4 50 100
5 3 46
Roman Perekhrest의 답변에는 확장된 예가 있습니다.
$ ./columns_max.py input.txt
1 40 76 78 99
2 20 98 98 93
3 34 33 77 111
4 50 100 33 66
5 3 46 44 9
작동 원리:
기본 아이디어는 첫 번째 열 항목으로 사전을 만드는 것입니다. 따라서 사전에는 1, 2, 3, 4 및 5 키가 있습니다. 사전 항목의 각 해당 값은 목록 목록이며, 각 하위 목록은 열에 해당합니다. 따라서 키 1의 경우 두 개의 목록을 포함하는 목록이 있습니다. 첫 번째는 모든 열 2 항목에 대한 것이고 두 번째는 모든 열 3 항목에 대한 것입니다. 기본적으로 다음과 같습니다.
('1', [ ['10', '4', '40'], ['15', '22', '76']] )
이제 이라는 정말 멋진 함수가 있는데 max()
, 이를 통해 숫자 목록을 가져와서 그 중에서 가장 큰 항목을 추출할 수 있습니다. 우리가 해야 할 일은 각 키를 반복하고 모든 목록을 가져와서 max()
여기에 기능을 적용하는 것뿐입니다.