수직과 수평으로 정렬하는 방법은 무엇입니까?

수직과 수평으로 정렬하는 방법은 무엇입니까?

이전(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컬럼 값을 기준으로 행을 정렬 하려고 합니다 .Hsort -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)]

관련 정보