GNU sort stable sort, wenn sort die Sortierreihenfolge nicht kennt


18

Ich habe eine zweispaltige Datei. Die Datei ist in Spalte 1 bereits so sortiert, wie ich es möchte. Ich möchte nach Spalte 2 in jeder Kategorie von Spalte 1 sortieren. Versteht sortjedoch nicht die Sortierreihenfolge von Spalte 1.

Der normale Weg (von ähnlichen Fragen hier auf Stapel) wäre dieser:

sort --stable -k1,1 -k2,2n

Die Sortierung für k1 kann ich aber nicht angeben, da sie willkürlich ist.

Beispiel Eingabe:

C 2
C 1
A 2
A 1
B 2 
B 1

und Ausgabe:

C 1
C 2
A 1
A 2
B 1 
B 2

Antworten:


20

Sie können awk verwenden, um für jeden Block eine neue Sortierung zu starten:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} - Wenn der gespeicherte Wert unterschiedlich ist, haben wir einen neuen Block, so dass wir alle zuvor gestarteten schließen sort
  • {print | "sort -k2,2"}'Leitet die Ausgabe an sortund startet sie, wenn sie noch nicht ausgeführt wird (awk kann Befehle verfolgen, die gestartet werden).

2
awk ist wirklich unglaublich. Ich mag das viel mehr als ich erwartet hatte, das war eine awk dekorieren-sortieren-undekorieren!
Evan Benn

Ich habe versucht, die Leistung dieser Antwort mit der anderen zu vergleichen, nicht sicher, warum diese mehr Ressourcen verwendet ... Irgendwelche Ideen? gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn

Wie viele Läufe haben Sie durchschnittlich gemacht?
muru

Ich habe keine Mittelwertbildung durchgeführt, sehe aber konstante Laufzeiten, wenn ich mich wiederhole und nachforsche.
Evan Benn

Hier ist eine ähnliche Datei zu dem, was ich verwende, wenn Sie untersuchen möchten:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn

12

Sie könnten eine Schwartzsche Transformation verwenden (dies ist im Grunde der Ansatz, den Sie in einem Kommentar als Dekorieren-Sortieren- Undekorieren bezeichnet haben , aber wahrscheinlich performanter als die gute Antwort von muru, weil Sie einen einzelnen sortAufruf anstelle von mehreren verwenden) - indem awkSie eine Präfixspalte hinzufügen, die Inkrementiert mit einer Wertänderung in der ersten Spalte, sortiert nach der Präfixspalte, gefolgt von der "zweiten" Spalte (deren Ordinalposition sich 3aufgrund des Vorhandenseins der Präfixspalte vorübergehend verschoben hat ), und entfernt schließlich die Präfixspalte

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-

Ich bin überrascht, aber Sie haben Recht, das war schneller als die andere Antwort! 3 Minuten versus 2 Minuten in meiner 100 Millionen Zeilen umfassenden Datei (~ 30 uniq erste Spalten).
Evan Benn

1
Es ist nicht erforderlich, ein Array des eindeutigen Schlüssels aus der ersten Spalte beizubehalten. Ich denke, es sollte ausreichen, die erste Spalte der aktuellen Zeile mit der vorherigen zu vergleichen.
Kusalananda

So etwas wie awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(ungetestet).
Kusalananda
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.