Zeilenblöcke sortieren


12

Ich habe eine Datei, die 4n Zeilen enthält. Hier ist ein Auszug mit 8 Zeilen

6115 8.88443
6116 6.61875
6118 16.5949
6117 19.4129
6116 6.619 
6117 16.5979 
6118 19.4111
6115 8.88433  

Ich möchte einen Block sortieren, wobei jeder Block aus 4 Zeilen besteht, basierend auf der ersten Spalte. Die Ausgabe für den Auszug sollte wie folgt aussehen.

6115 8.88443
6116 6.61875
6117 19.4129
6118 16.5949
6115 8.88433 
6116 6.619 
6117 16.5979 
6118 19.4111 

Antworten:


17

Eine Möglichkeit besteht darin, zu verwenden, um alle N Zeilen ein anfängliches Seriennummernpräfix hinzuzufügen (in Ihrem Fall N = 4). Tragen Sie dann das Präfix als primäre Sortierspalte ein sort.

Beispiel mit N = 4:

awk '{print int((NR-1)/4), $0}' file.txt | sort -n -k1,1 -k2,2 | cut -f2- -d' '

7

Wenn dies einmalig ist und Sie nicht Python, Perl oder awk lernen möchten, können Sie mit den grundlegenden splitund sortBefehlen fortfahren.

Teilen Sie zuerst die Datei in 4 Zeilenblöcke mit der -l Option:

split -a 6 -l 4 input_file my_prefix_
for fn in my_prefix_*; do
    sort -n -o $fn $fn
done
cat my_prefix_* > output_file
rm my_prefix_*

Die sort -nSortierung nach numerischem Wert der ersten Spalte (999 vor 1234). -a 6sollte sich um eine Datei mit 26 ^ 6 * 4 Zeilen kümmern. my_prefix_sollte für das Verzeichnis, mit dem Sie arbeiten, eindeutig sein.


3

Sie können es mit Perl tun:

perl -nle '
   push @a,$_;
   unless($. % 4){
       print join "\n",sort {$a <=> $b} @a; # Sort @a, and print its contents
       @a = (); # Empty @a to start a new block
   }
' your_file

Wie das geht

  • -n-> Code für jede Eingabezeile ausführen (und die aktuelle Zeile einfügen $_)
  • -l -> füge eine neue Zeile an die Ausgabe von any an print
  • -e -> folgenden String als Perl-Code ausführen
  • Jede Zeile wird an das Array angehängt @a.
  • $.hält die aktuelle Zeilennummer und wenn diese Nummer nicht mit Null Modulo 4 übereinstimmt, arbeiten wir weiter. Wenn es zu Null Modulo 4 kongruent ist , haben wir eine Zeile erreicht, deren Nummer ein Vielfaches von 4 ist (das Ende eines Blocks). In diesem Fall sortieren wir die Einträge @ain aufsteigender numerischer Reihenfolge und drucken sie im sortierten Array aus durch einen Zeilenvorschub zur Standardausgabe verbunden.

2

Unter Verwendung einer Bourne-ähnlichen Shell

while read a ; do                                           # Try reading a line.
    read b ; read c ; read d                                # OK, read 3 more.
    printf '%s\n%s\n%s\n%s\n' "$a" "$b" "$c" "$d" | sort -n # Sort them.
done < data

2

Hier sind einige "reine" awkLösungen:

Wenn die Indizes immer die gleiche inkrementelle Ganzzahlfolge (6115-6119) wie in Ihren Beispieldaten haben, können Sie eine algorithmische "Verknüpfung" verwenden:

awk '{a[$1]=$0} !(NR%4){for(i=6115;i<6119;print a[i++]);}'

Das macht

  • Fügen Sie dem Array alle Zeilen hinzu, die aan den Indexpositionen 6115-6119 verteilt sind
  • !(NR%4)Durchlaufen Sie in jeder vierten Zeile ( ) den Inhalt des Arrays, um in der gewünschten Reihenfolge zu drucken.

Wenn Ihre numerischen Indizes immer die gleichen vier sind, aber keine inkrementelle Ganzzahlfolge, müssen Sie sortieren:

awk '{a[$1]=$0} !(NR%4){asort(a,b); for(i=1;i<5;print b[i++]);}'

Hinweis: Dies ist bei GNU awk der Fall, andere unterstützen dies möglicherweise nicht asort.


Wenn jeder Viererblock unterschiedliche numerische IDs haben könnte:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;print a[i++]); delete a}'

Hinweis: Bisdelete von @Gilles Selbstantwort (+2) ist diese Verwendung (noch) nicht POSIX, aber universell unterstützt .


Eine Version mit der korrekten Verwendung von delete:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;delete a[i++]){print a[i]}}'

Eine Version ohne Löschen mit mehr Speicher und Abmessungen:

awk '{a[n][$1]=$0} !(NR%4){asort(a[n]); for(i=1;i<5;print a[n][i++]); n++}

1

Mit R erhalten Sie eine saubere Lösung. Wenn sich die obige Tabelle in einer Datei mit dem Namen "table.txt" befindet, führen Sie die folgenden Schritte aus. Das gewünschte Ergebnis befindet sich in der Datei "tableout.txt".

> x = read.table("table.txt", col.names=c("a", "b"))
> x
     a        b
1 6115  8.88443
2 6116  6.61875
3 6118 16.59490
4 6117 19.41290
5 6116  6.61900
6 6117 16.59790
7 6118 19.41110
8 6115  8.88433
> x["index"] = c(rep(1, 4), rep(2, 4))
> x
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
3 6118 16.59490     1
4 6117 19.41290     1
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
8 6115  8.88433     2     
> xord = x[with(x, order(index, a)), ]
> xord
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
4 6117 19.41290     1
3 6118 16.59490     1
8 6115  8.88433     2
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
> write.table(xord[,1:2], "tableout.txt", row.names=FALSE, col.names=FALSE)

Siehe auch Wie in R einen Datenrahmen durch Spalte (n) sortieren .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.