之前(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 列和行进行垂直和水平排序?
截图:
前:
后:
问题有两个,首先你想#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 也是如此
这相对容易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)