이전(INPUT.txt):
Foo#1 Foo#2 Foo#3 Foo#4 Foo#4 Foo#5 SUM
Bar#1 0 0 0 0 3 0 3
Bar#2 2 0 1 0 0 0 3
Bar#3 0 0 0 2 2 0 4
Bar#4 0 0 1 1 2 0 4
Bar#5 1 0 1 0 0 0 2
Bar#6 3 20 0 0 1 0 24
Bar#7 1 0 2 0 0 0 3
SUM 7 20 5 3 8 0 43
이후(OUTPUT.txt):
Foo#2 Foo#4 Foo#1 Foo#3 Foo#4 Foo#5 SUM
Bar#6 20 1 3 0 0 0 24
Bar#3 0 2 0 0 2 0 4
Bar#4 0 2 0 1 1 0 4
Bar#1 0 3 0 0 0 0 3
Bar#2 0 0 2 1 0 0 3
Bar#7 0 0 1 2 0 0 3
Bar#5 0 0 1 1 0 0 2
SUM 20 8 7 5 3 0 43
어려운 질문:Bash 또는 Perl에서 SUM 열과 행을 기준으로 수직 및 수평으로 정렬하는 방법은 무엇입니까?
스크린샷:
앞으로:
뒤쪽에:
답변1
문제는 두 가지입니다. 먼저 대부분의 행 기반 명령줄 도구에서 상당히 간단한 정렬 작업인 #bar
컬럼 값을 기준으로 행을 정렬 하려고 합니다 .H
sort -nr -k8,1 input.txt |column -t > intermediate1.txt
테이블의 헤더 및 합계 행에는 일부 수동 섞기가 필요하지만 그 이후의 중간 결과는 다음과 같습니다.
- Foo#1 Foo#2 Foo#3 Foo#4 Foo#4 Foo#5 SUM
Bar#6 3 20 0 0 1 0 24
Bar#4 0 0 1 1 2 0 4
Bar#3 0 0 0 2 2 0 4
Bar#7 1 0 2 0 0 0 3
Bar#2 2 0 1 0 0 0 3
Bar#1 0 0 0 0 3 0 3
Bar#5 1 0 1 0 0 0 2
SUM 7 20 5 3 8 0 43
두 번째는 좀 더 복잡하며 맨 아래 행의 열 합계 값을 기준으로 열을 섞습니다.
처음 문제를 해결하면 더 쉽게 풀 수 있습니다.바꾸어 놓다귀하의 행렬은 열을 행으로 또는 그 반대로 전환합니다. 왜냐하면 귀하의 작업은 다시 간단한 열 정렬이기 때문입니다. 이것을 사용GNU awk 코드스택 오버플로에서:
awk '
{
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p { p = NF }
END {
for(j=1; j<=p; j++) {
str=a[1,j]
for(i=2; i<=NR; i++){
str=str" "a[i,j];
}
print str
}
}' intermediate1.txt | column -t > intermediate2.txt
다음 중간 결과를 얻으세요:
- Bar#6 Bar#4 Bar#3 Bar#7 Bar#2 Bar#1 Bar#5 SUM
Foo#1 3 0 0 1 2 0 1 7
Foo#2 20 0 0 0 0 0 0 20
Foo#3 0 1 0 2 1 0 1 5
Foo#4 0 1 2 0 0 0 0 3
Foo#4 1 2 2 0 0 3 0 8
Foo#5 0 0 0 0 0 0 0 0
SUM 24 4 4 3 3 3 2 43
이제 이 행렬은 합계 열의 값을 기준으로 정렬할 수 있으며 sort -k9,1 -nr intermediate2.txt > intermediate3.txt
, 머리글 및 합계 행의 순서를 수동으로 수정한 후 행렬은 다음과 같습니다.
- Bar#6 Bar#4 Bar#3 Bar#7 Bar#2 Bar#1 Bar#5 SUM
Foo#2 20 0 0 0 0 0 0 20
Foo#4 1 2 2 0 0 3 0 8
Foo#1 3 0 0 1 2 0 1 7
Foo#3 0 1 0 2 1 0 1 5
Foo#4 0 1 2 0 0 0 0 3
Foo#5 0 0 0 0 0 0 0 0
SUM 24 4 4 3 3 3 2 43
그런 다음 이전과 동일한 awk 코드를 사용하여 위의 중간 결과를 원래 열 및 행 레이아웃으로 다시 변환합니다.
awk '
{
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p { p = NF }
END {
for(j=1; j<=p; j++) {
str=a[1,j]
for(i=2; i<=NR; i++){
str=str" "a[i,j];
}
print str
}
}' intermediate3.txt | column -t > output.txt
형식이 잘 지정된 결과:
- Foo#2 Foo#4 Foo#1 Foo#3 Foo#4 Foo#5 SUM
Bar#6 20 1 3 0 0 0 24
Bar#4 0 2 0 1 1 0 4
Bar#3 0 2 0 0 2 0 4
Bar#7 0 0 1 2 0 0 3
Bar#2 0 0 2 1 0 0 3
Bar#1 0 3 0 0 0 0 3
Bar#5 0 0 1 1 0 0 2
SUM 20 8 7 5 3 0 43
Bar#4와 Bar#3의 순서는 합계 값이 동일하기 때문에 예시 결과와 반대이지만 A열도 Bar#7, Bar#2, Bar#과 마찬가지로 내림차순을 따릅니다. 1
답변2
이는 비교적 쉽습니다 perl
.
perl -F'\s+' -lane '
push @row, [@F];
END{
@sum = @{pop @row};
@col = (0, (sort {$sum[$b] <=> $sum[$a]} (1..$#sum-1)), $#sum);
for $i ($row[0], (sort {$b->[$#sum] <=> $a->[$#sum]} @row[1..$#row]), \@sum) {
print join "\t", @{$i}[@col]
}
}'
답변3
참고로 python
해결책입니다.
from pprint import pprint
x = [(0,0,0,0,3,0),
(2,0,1,0,0,0),
(0,0,0,2,2,0),
(0,0,1,1,2,0),
(1,0,1,0,0,0),
(3,20,0,0,1,0),
(1,0,2,0,0,0)
]
y = sorted(x, key=sum, reverse=True)
pprint(zip(*sorted(zip(*y), key=sum, reverse=True)))
[(20, 1, 3, 0, 0, 0),
(0, 2, 0, 0, 2, 0),
(0, 2, 0, 1, 1, 0),
(0, 3, 0, 0, 0, 0),
(0, 0, 2, 1, 0, 0),
(0, 0, 1, 2, 0, 0),
(0, 0, 1, 1, 0, 0)]