之前(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
按 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
第二个有点复杂,根据底行中的列总和值对列进行洗牌。
当你第一次时,问题会变得更容易解决转置您的矩阵,即将列切换为行,反之亦然,因为这样您的操作又是一个简单的列排序。使用这个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
现在可以根据 sum 列 的值对该矩阵进行排序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)]