如何纵向和横向排序?

som*_*533 7 sort

之前(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
Run Code Online (Sandbox Code Playgroud)

之后(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
Run Code Online (Sandbox Code Playgroud)

棘手的问题:如何在 bash 或 perl 中按 SUM 列和行进行垂直和水平排序?

截图:

前:

在此处输入图片说明

后:

在此处输入图片说明

HBr*_*ijn 6

问题有两个,首先你想#bar按 column 的数值对行进行排序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
Run Code Online (Sandbox Code Playgroud)

第二个有点复杂,根据底行中的列总和值对列进行洗牌。

当您第一次转置矩阵时,问题变得更容易解决,即将列切换到行,反之亦然,因为您的操作再次是简单的列排序。使用来自堆栈溢出的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
Run Code Online (Sandbox Code Playgroud)

得到下一个中​​间结果:

-      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
Run Code Online (Sandbox Code Playgroud)

该矩阵现在可以根据 sum column 的值进行排序sort -k9,1 -nr intermediate2.txt > intermediate3.txt,在手动更正标题和 sum 行的顺序后,该值如下所示:

-      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
Run Code Online (Sandbox Code Playgroud)

然后使用与之前相同的 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
Run Code Online (Sandbox Code Playgroud)

以及格式良好的结果:

-      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
Run Code Online (Sandbox Code Playgroud)

Bar#4 和 Bar#3 的顺序与示例结果相反,因为总和值相同,但在 A 列中也遵循降序排序,Bar#7、Bar#2 和 Bar#1 也是如此


Sté*_*las 3

这相对容易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]
    }
  }'
Run Code Online (Sandbox Code Playgroud)