Bei einem Array von Zeichenfolgen möchte ich das Array nach der Länge jedes Elements sortieren.
Zum Beispiel...
array=(
"tiny string"
"the longest string in the list"
"middle string"
"medium string"
"also a medium string"
"short string"
)
Sollte sortieren nach ...
"the longest string in the list"
"also a medium string"
"medium string"
"middle string"
"short string"
"tiny string"
(Als Bonus wäre es schön, wenn die Liste Zeichenfolgen gleicher Länge alphabetisch sortieren würde. Im obigen Beispiel medium string
wurde sie zuvor sortiert middle string
, obwohl sie dieselbe Länge haben. Dies ist jedoch keine "harte" Anforderung, wenn dies die Lösung).
Es ist in Ordnung, wenn das Array direkt sortiert ist (dh "Array" wird geändert) oder wenn ein neues sortiertes Array erstellt wird.
bash
shell-script
sort
array
PJ Singh
quelle
quelle
Antworten:
Wenn die Zeichenfolgen keine Zeilenumbrüche enthalten, sollte Folgendes funktionieren. Es sortiert die Indizes des Arrays nach der Länge, wobei die Zeichenfolgen selbst als sekundäres Sortierkriterium verwendet werden.
Beachten Sie, dass die Umstellung auf eine echte Programmiersprache die Lösung erheblich vereinfachen kann, z. B. in Perl
quelle
sorted(array, key=lambda s: (len(s), s))
array.sort { |a| a.size }
Dies liest die Werte des sortierten Arrays aus einer Prozessersetzung.
Die Prozessersetzung enthält eine Schleife. Die Schleife gibt jedes Element des Arrays aus, dem die Länge des Elements und ein Tabulatorzeichen dazwischen vorangestellt sind.
Die Ausgabe der Schleife wird numerisch vom größten zum kleinsten sortiert (und alphabetisch, wenn die Längen gleich sind;
-k 2r
anstelle von-k 2
, um die alphabetische Reihenfolge umzukehren), und das Ergebnis davon wird gesendet, ancut
das die Spalte mit den Zeichenfolgenlängen gelöscht wird.Sortieren Sie das Testskript, gefolgt von einem Testlauf:
Dies setzt voraus, dass die Zeichenfolgen keine Zeilenumbrüche enthalten. Auf GNU-Systemen mit einer aktuellen
bash
Version können Sie eingebettete Zeilenumbrüche in den Daten unterstützen, indem Sie anstelle von Zeilenumbrüchen das Nullzeichen als Datensatztrennzeichen verwenden:Hier werden die Daten mit Nachlauf
\0
in der Schleife anstelle von Zeilenumbrüchen gedruckt, diesort
undcut
lesen nicht begrenzte Zeilen durch ihre-z
GNU-Optionen undreadarray
lesen schließlich die nicht begrenzten Daten mit-d ''
.quelle
-d '\0'
in der Tat-d ''
alsbash
nicht NUL - Zeichen auf Befehle passieren kann, auch seine builtins. Aber es versteht sich-d ''
als Abgrenzung auf NUL . Beachten Sie, dass Sie dafür Bash 4.4+ benötigen.'\0'
, das ist es$'\0'
. Und ja, es konvertiert (fast genau) in''
. Aber das ist ein Weg , um comunicate andere Leser der eigentlichen Absicht , ein NUL Trennzeichen verwenden.Ich werde nicht vollständig wiederholen, was ich bereits über das Sortieren in Bash gesagt habe. Sie können nur innerhalb von Bash sortieren, aber vielleicht sollten Sie es nicht. Im Folgenden finden Sie eine Nur-Bash-Implementierung einer Einfügungssortierung, die O (n 2 ) ist und daher nur für kleine Arrays toleriert werden kann. Es sortiert die vorhandenen Array-Elemente nach ihrer Länge in absteigender Reihenfolge. Es wird keine sekundäre alphabetische Sortierung durchgeführt.
Betrachten Sie als Beweis dafür, dass dies eine spezielle Lösung ist, die Zeitabläufe der vorhandenen drei Antworten auf Arrays unterschiedlicher Größe:
Choroba und Kusalananda haben die richtige Idee: Berechnen Sie die Längen einmal und verwenden Sie spezielle Dienstprogramme zum Sortieren und Verarbeiten von Text.
quelle
Ein Hackish? (komplexe) und schnelle einzeilige Methode zum Sortieren des Arrays nach Länge
( sicher für Zeilenumbrüche und spärliche Arrays):
In einer Zeile:
Bei der Ausführung
quelle
Dies behandelt auch Array-Elemente mit Zeilenumbrüchen. Es funktioniert, indem
sort
nur die Länge und der Index jedes Elements durchlaufen werden . Es sollte mitbash
und funktionierenksh
.Wenn die Elemente gleicher Länge auch lexikografisch sortiert werden müssen, kann die Schleife folgendermaßen geändert werden:
Dies wird auch an
sort
die Zeichenfolgen übergeben (wobei Zeilenumbrüche in Leerzeichen geändert werden), sie werden jedoch weiterhin von ihren Indizes von der Quelle in das Zielarray kopiert. In beiden Beispielen$(...)
werden nur Zeilen angezeigt, die Zahlen enthalten (und das/
Zeichen im ersten Beispiel), sodass es nicht durch Globbing-Zeichen oder Leerzeichen in den Zeichenfolgen ausgelöst wird.quelle
$(...)
Befehlssubstitution aufgrund der Nachsortierung nur die Indizes (eine durch Zeilenumbrüche getrennte Liste von Zahlen) angezeigtcut -d' ' -f1
. Dies konnte leicht durch eintee /dev/tty
am Ende des$(...)
.cut
.${!in[@]}
oder${#in[i]}/$i
Variablenerweiterungen in Anführungszeichen zu setzen, da sie nur Ziffern enthalten, die keiner Glob-Erweiterung unterliegen, undunset IFS
dieIFS
auf Leerzeichen, Tabulatoren und Zeilenumbrüche zurücksetzen. In der Tat wäre das Zitieren schädlich , da es den falschen Eindruck erweckt, dass ein solches Zitieren nützlich und effektiv ist und dass das EinstellenIFS
und / oder Filtern der Ausgabesort
im zweiten Beispiel sicher beseitigt werden könnte.in
enthält"testing * here"
undshopt -s nullglob
vor der Schleife gesetzt wird.Für den Fall, dass ein Wechsel zu
zsh
eine Option ist, ein hackiger Weg dorthin (für Arrays, die eine beliebige Folge von Bytes enthalten):zsh
Ermöglicht das Definieren von Sortierreihenfolgen für die Glob-Erweiterung über Glob-Qualifizierer. Hier täuschen wir es also vor, es für beliebige Arrays zu tun, indem wir es globalisieren/
, aber durch/
die Elemente des Arrays ersetzen (e'{reply=("$array[@]")}'
) und dann die Elemente basierend auf ihrer Länge ( )n
umerischo
umordnen (umgekehrt mit Großbuchstaben ).O
Oe'{REPLY=$#REPLY}'
Beachten Sie, dass dies auf der Länge der Anzahl der Zeichen basiert. Setzen Sie für die Anzahl der Bytes das Gebietsschema auf
C
(LC_ALL=C
).Ein
bash
weiterer Ansatz von 4.4+ (unter der Annahme eines nicht zu großen Arrays):(das ist die Länge in Bytes ).
Mit älteren Versionen von
bash
können Sie immer Folgendes tun:(was auch mit arbeiten würde
ksh93
,zsh
,yash
,mksh
).quelle