Wie vertikal und horizontal sortieren?

7

Vorher (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

Nach (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

Schwierige Frage: Wie sortiere ich vertikal und horizontal nach der SUM-Spalte und -Zeile in Bash oder Perl?

Screenshots:

Vor:

Geben Sie hier die Bildbeschreibung ein

Nach:

Geben Sie hier die Bildbeschreibung ein

somelooser28533
quelle

Antworten:

3

Das ist relativ einfach mit 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]
    }
  }'
Stéphane Chazelas
quelle
Ich denke du bist nicht normal. Bist du ein Alien? : D Danke: D
somelooser28533
Relativ einfach? Relativ zu was?
Dotancohen
Einfacher als es in Assembler zu schreiben :)
Barmar
6

Das Problem ist zweifach: Zuerst möchten Sie die #barZeilen nach dem numerischen Wert der Spalte Hsortieren. Dies ist in den meisten zeilenorientierten Befehlszeilenwerkzeugen eine ziemlich triviale Sortieroperation.sort -nr -k8,1 input.txt |column -t > intermediate1.txt

Der Header Ihrer Tabelle und die Summenzeile erfordern ein manuelles Mischen, danach jedoch ein Zwischenergebnis von:

-      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

Die zweite ist etwas komplexer. Mischen Sie die Spalten basierend auf den Spaltensummenwerten in der unteren Zeile.

Das Problem wird viel einfacher zu lösen, wenn Sie Ihre Matrix zum ersten Mal transponieren , dh die Spalten in Zeilen umschalten und umgekehrt, da Ihre Operation dann wieder eine einfache Spaltensortierung ist. Verwenden dieses GNU awk-Codes aus dem Stapelüberlauf:

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

erhält das nächste Zwischenergebnis:

-      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

Diese Matrix kann nun nach dem Wert der Summenspalte sortiert werden sort -k9,1 -nr intermediate2.txt > intermediate3.txt, die nach manueller Korrektur der Reihenfolge der Kopf- und Summenzeilen wie folgt aussieht:

-      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

Transponieren Sie dann mit demselben awk-Code wie zuvor das Zwischenergebnis oben zurück, um zu Ihrem ursprünglichen Layout von Spalten und Zeilen zurückzukehren:

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

und das schön formatierte Ergebnis:

-      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

Die Reihenfolge von Takt Nr. 4 und Takt Nr. 3 ist gegenüber dem Beispielergebnis umgekehrt, da der Summenwert identisch ist. Die absteigende Sortierreihenfolge wird jedoch auch in Spalte A befolgt, ebenso wie für Takt Nr. 7, Takt Nr. 2 und Takt Nr. 1

HBruijn
quelle
Danke vielmals! Die Perl ist kürzer, wow: \
somelooser28533
2

Für die Aufzeichnung eine pythonLösung.

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)]
iruvar
quelle