(gelöst) Wie kann ich das sortieren?

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
medias
Beiträge: 90
Registriert: 18.05.2014 11:21:43

(gelöst) Wie kann ich das sortieren?

Beitrag von medias » 01.05.2017 23:42:24

Wie kann ich diese Zeilen sortieren:

17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein zwei drei vier Wort. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein Wort. (Uwort)

... damit ich dieses Sortier-Ergebnis erreiche:

2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)

Sortiert wird zuerst die erste Spalte z. B. 2.194 und so weiter und als zweiten und letzten Sortiervorgang nach dem letzten Wort der Zeile z. B. (Dwort).

Wenn ich meinen Text in eine Excel Tabelle kopiere und in Excel sortiere ist es kein Problem. Mit sort schaffe ich es nicht. Es ergibt nur Chaos. Wie sortiere ich mit sort?
Zuletzt geändert von medias am 04.05.2017 17:39:30, insgesamt 1-mal geändert.

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 02.05.2017 00:39:48

Wie ist das:

Code: Alles auswählen

sort -t '(' -k1n -k2

maroc

Re: Wie kann ich das sortieren?

Beitrag von maroc » 02.05.2017 00:54:46

Vielleicht eher so?

Code: Alles auswählen

sort -t "." -k1n,1 -k3

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 02.05.2017 01:03:38

Dann reißt du aber die Dezimalzahl auseinander!?
Dann eher so:

Code: Alles auswählen

sort -t "." -k1n -k3

maroc

Re: Wie kann ich das sortieren?

Beitrag von maroc » 02.05.2017 01:10:29

@tobo
Wenn ich das nicht falsch sehe (z. B. wg. Übermüdung :wink: ), sortieren Deine beiden Vorschläge nicht im Sinne des Fragestellers, da sie die mit "17.1" beginnenden Zeilen vor die mit "2.194" sortieren statt dahinter?!

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 02.05.2017 01:14:30

Also hier kommt das schon richtig raus!? 2.194 zuerst...

maroc

Re: Wie kann ich das sortieren?

Beitrag von maroc » 02.05.2017 01:20:49

Merkwürdig! Aus meinem Terminal kopiert:

Code: Alles auswählen

$ cat beispiel.txt
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein zwei drei vier Wort. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein Wort. (Uwort)
$ sort -t '(' -k1n -k2 beispiel.txt
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 02.05.2017 01:38:10

Und das aus meinem:

Code: Alles auswählen

$ cat beispiel.txt 
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein zwei drei vier Wort. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein Wort. (Uwort)
$ sort -t '(' -k1n -k2 beispiel.txt
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
XTerm(327); sort (GNU coreutils) 8.23 bzw. Heirloom Toolchest; LC_COLLATE=C; der Rest LC_*=en_US.UTF-8

PS: Wegen der numerischen Sortierung muss das ja eigentlich auch nicht auf das erste Feld (mit ,1) beschränkt werden!? Anders wäre es, wenn hier nach Zeichen sortiert werden würde.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 02.05.2017 06:58:39

maroc hat geschrieben:Merkwürdig! Aus meinem Terminal kopiert:

Code: Alles auswählen

$ cat beispiel.txt
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein zwei drei vier Wort. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein Wort. (Uwort)
$ sort -t '(' -k1n -k2 beispiel.txt
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)
Diese Reihenfolge kann ich nicht nachvollziehen. Wenn die erste Spalte numerisch sortiert wird, dann sollte das nie zu diesem Ergebnis fuehren, egal in welchem Locale. (Irgendwas scheine ich noch zu uebersehen ... oder es war keine 1:1-Kopie der Shellsession ...)

Natuerlich ist das Locale LC_COLLATE bei sort(1) grundsaetzlich immer entscheidend, darum sollte das bei solchen Aufgaben immer explizit gesetzt werden.

Aus meiner Sicht hat tobo passende Antworten geliefert.
Use ed once in a while!

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: Wie kann ich das sortieren?

Beitrag von newdeb » 02.05.2017 07:38:54

Meillo hat geschrieben:Natuerlich ist das Locale LC_COLLATE bei sort(1) grundsaetzlich immer entscheidend, darum sollte das bei solchen Aufgaben immer explizit gesetzt werden.
Und LC_NUMERIC nicht vergessen:

Code: Alles auswählen

$ LC_NUMERIC="de_DE.UTF-8" sort -t '(' -k1n -k2 bsp.txt
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)

$ LC_NUMERIC=C sort -t '(' -k1n -k2 bsp.txt
2.194 Ein fünf sechs Wort. (Awort)
2.194 Ein zwei Wort. (Dwort)
2.194 Ein Wort. (Uwort)
2.194 Ein zwei drei vier Wort. (Xwort)
17.1 Eins zwei drei vier fünf sechs Worte. (Awort)
17.1 Eins zwei drei vier fünf Worte. (Dwort)
17.1 Eins zwei drei vier sechs Worte. (Uwort)
17.1 Eins zwei vier fünf Worte. (Xwort)
Oder auch so :)

Code: Alles auswählen

LC_NUMERIC="de_DE.UTF-8" sed 's/\./,/' bsp.txt | sort -t '(' -k1n -k2 | sed 's/,/./'

maroc

Re: Wie kann ich das sortieren?

Beitrag von maroc » 02.05.2017 09:24:39

newdeb hat geschrieben:Und LC_NUMERIC nicht vergessen:
Danke, das macht tatsächlich den Unterschied. Ich hatte LC_NUMERIC="de_DE.UTF-8", und da wird das Komma (statt des Punktes) als Dezimaltrenner verwendet.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 02.05.2017 09:34:18

newdeb hat geschrieben: Und LC_NUMERIC nicht vergessen:
Ja, danke!
Oder auch so :)

Code: Alles auswählen

LC_NUMERIC="de_DE.UTF-8" sed 's/\./,/' bsp.txt | sort -t '(' -k1n -k2 | sed 's/,/./'
Nein, so:

Code: Alles auswählen

sed 's/\./,/' bsp.txt | LC_NUMERIC="de_DE.UTF-8" sort -t '(' -k1n -k2 | sed 's/,/./'
;-)
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 02.05.2017 09:44:20

maroc hat geschrieben:
newdeb hat geschrieben:Und LC_NUMERIC nicht vergessen:
Danke, das macht tatsächlich den Unterschied. Ich hatte LC_NUMERIC="de_DE.UTF-8", und da wird das Komma (statt des Punktes) als Dezimaltrenner verwendet.
Aber ich versteh's immer noch nicht. Ist es nicht so, dass bei numerischer Sortierung der String in eine Zahl konvertiert wird, und zwar (wie bei atoi(3)) der Anfang des Strings bis zum ersten Nicht-Zahl-Zeichen. Im englischen Fall waere das erste Nicht-Zahl-Zeichen der Space und damit findet man die Zahlen ``2.194'' bzw. ``17.1''. Im deutschen Fall ist das erste Nicht-Zahl-Zeichen der Punkt und damit findet man nur ``2'' und ``17''. In beiden Faellen waere aber die 2 numerische kleiner, egal ob mit oder ohne die Kommastellen.

Versteht ihr mein Problem beim Nachvollziehen der Ausgabe?

... ausser, bei ``2.194'' wird der Punkt als Tausendertrenner interpraetiert, weil genau drei Stellen folgen, was bei ``17.1'' nicht der Fall ist. Damit waere der Vergleich zwischen ``2194'' und ``17'', wovon natuerlich ersteres groesser ist.

Hey, da sollte ich jetzt eintauchen! Das hoert sich super interessant an. Auch will ich schon lange in POSIX studieren wie das bei sort(1) genau funktioniert ... Hoffentlich finde ich dazu die Zeit.
Use ed once in a while!

maroc

Re: Wie kann ich das sortieren?

Beitrag von maroc » 02.05.2017 10:14:08

Meillo hat geschrieben:Ist es nicht so, dass bei numerischer Sortierung der String in eine Zahl konvertiert wird, und zwar (wie bei atoi(3)) der Anfang des Strings bis zum ersten Nicht-Zahl-Zeichen. Im englischen Fall waere das erste Nicht-Zahl-Zeichen der Space und damit findet man die Zahlen ``2.194'' bzw. ``17.1''. Im deutschen Fall ist das erste Nicht-Zahl-Zeichen der Punkt und damit findet man nur ``2'' und ``17''. In beiden Faellen waere aber die 2 numerische kleiner, egal ob mit oder ohne die Kommastellen.
In meinem, allerdings laienhaften, Verständnis sieht es so aus, als ob sort im deutschen Fall den Punkt einfach ignoriert, warum auch immer. Deshalb sortiert "17.1" (171) vor "2.194" (2194), aber etwa "2.1" (21) vor "17.1" (171).

Code: Alles auswählen

$ echo -e  "17.1\n2.194" | sort -n
17.1
2.194
$ echo -e  "17.1\n2.1" | sort -n
2.1
17.1
EDIT: Wobei, okay, das wirklich die dahinterstehende Erklärung sein könnte:
Meillo hat geschrieben:... ausser, bei ``2.194'' wird der Punkt als Tausendertrenner interpraetiert, weil genau drei Stellen folgen, was bei ``17.1'' nicht der Fall ist.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 02.05.2017 15:06:51

Meillo hat geschrieben: ... ausser, bei ``2.194'' wird der Punkt als Tausendertrenner interpraetiert, weil genau drei Stellen folgen, was bei ``17.1'' nicht der Fall ist. Damit waere der Vergleich zwischen ``2194'' und ``17'', wovon natuerlich ersteres groesser ist.
Mit der Vermutung habe ich ziemlich sicher recht, denn hier wird der Tausendertrenner explizit erwaehnt:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html hat geschrieben: -n
Restrict the sort key to an initial numeric string, consisting of optional <blank> characters, optional <hyphen-minus> character, and zero or more digits with an optional radix character and thousands separators (as defined in the current locale), which shall be sorted by arithmetic value.
Tausendertrenner werden einfach ignoriert als seien sie nicht da, wie hier erahnt werden kann:

Code: Alles auswählen

$ printf '102\n1.03\n10.1\n10.0\n1.01\n101'| LC_ALL=de_DE.UTF-8 sort -n
10.0
1.01
101
10.1
102
1.03
Das sind alles (falsch plazierte) Tausendertrenner, keine Dezimalkommas! Die Zahlwerte sind 100, 101 (3x), 102 und 103.


Damit als kleine Korrektur zu meiner ersten Vermutung: Es ist egal wie etwaige Tausendertrenner plaziert sind, somit wir im Originalbeispiel zwischen ``2194'' und ``171'' vergleichen.
Use ed once in a while!

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 02.05.2017 23:09:43

Meillo hat geschrieben:Tausendertrenner werden einfach ignoriert als seien sie nicht da, wie hier erahnt werden kann:

Code: Alles auswählen

$ printf '102\n1.03\n10.1\n10.0\n1.01\n101'| LC_ALL=de_DE.UTF-8 sort -n
10.0
1.01
101
10.1
102
1.03
Also bei mir werden die Trenner nicht vollständig ignoriert!? Als numerischer Trenner schon, aber der Punkt wandert innerhalb der 101er-Gruppe von links nacht rechts:

Code: Alles auswählen

$ printf '102\n1.03\n10.1\n10.0\n1.01\n101'| LC_ALL=de_DE.UTF-8 sort -n
10.0
101
1.01
10.1
102
1.03
Besser sichtbar hier:

Code: Alles auswählen

$ printf '10.001\n100.01\n1.0001\n1000.1\n10001\n'| LC_ALL=de_DE.UTF-8 sort -n
10001
1.0001
10.001
100.01
1000.1

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 03.05.2017 07:04:19

tobo hat geschrieben: Also bei mir werden die Trenner nicht vollständig ignoriert!? Als numerischer Trenner schon, aber der Punkt wandert innerhalb der 101er-Gruppe von links nacht rechts:
Ich wuerde das als Implementierungsbesonderheit werten.

Wenn alle ``Darstellungen'' innerhalb der 101er-Gruppe als zahlenmaessig gleichwertig erachtet werden, dann ist undefiniert in welcher Reihenfolge sie kommen ... ausser du verwendest `-s' (stabilized sort), dann sollten sie in der Reihenfolge der Eingabe erscheinen.
Use ed once in a while!

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 03.05.2017 12:33:27

Meillo hat geschrieben:Ich wuerde das als Implementierungsbesonderheit werten.

Wenn alle ``Darstellungen'' innerhalb der 101er-Gruppe als zahlenmaessig gleichwertig erachtet werden, dann ist undefiniert in welcher Reihenfolge sie kommen
Das mag sein. Bei mir tritt diese Besonderheit jedoch in der GNU-, Heirloom, Busybox- und Suckless-Variante von sort auf. Welches sort erzeugte denn bei dir die Ausgabe?

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 03.05.2017 12:56:03

tobo hat geschrieben: Bei mir tritt diese Besonderheit jedoch in der GNU-, Heirloom, Busybox- und Suckless-Variante von sort auf. Welches sort erzeugte denn bei dir die Ausgabe?
sort (GNU coreutils) 8.13, auf Debian oldstable. (Es koennte evtl. auch am Locale liegen, k.A.: locale (Debian EGLIBC 2.13-38+deb7u11) 2.13)

Meine Gedanken sind folgende:

Ist der zahlenmaessige Wert von ``10.1'' und ``1.01'' gleich? Wenn ja, dann unterliegt die Reihenfolge nur der Implementierung des Sortieralgorithmuses. Jedenfalls kenne ich keine inhaltliche Logik fuer eine sinnvolle Ordnung dieser zwei invalider Notationen.

Die einzige Regel, die fuer mich Sinn macht, ist das Ignorieren von Tausendertrennern, egal an welchen Stellen sie stehen. (Das ist auch implementatorisch gut umsetzbar ... und damit wahrscheinlich so auch umgesetzt.)

Interessant ist, dass `-nu' die zahlenmaessig gleichen Werte ``10.1'' und ``1.01'' nicht vereint, waehrend ``100'' und ``100,0'' zusammenfallen! ... vielleicht ist das aber auch nur ein undefiniertes Verhalten und die Folge von ``garbage in, garbage out''.
Use ed once in a while!

tobo
Beiträge: 1964
Registriert: 10.12.2008 10:51:41

Re: Wie kann ich das sortieren?

Beitrag von tobo » 03.05.2017 14:00:26

Meillo hat geschrieben:Die einzige Regel, die fuer mich Sinn macht, ist das Ignorieren von Tausendertrennern, egal an welchen Stellen sie stehen. (Das ist auch implementatorisch gut umsetzbar ... und damit wahrscheinlich so auch umgesetzt.)
Würden die "vollständig" ignoriert werden, dann sollte doch die Reihenfolge der 101er im printf entscheidend für die Ausgabe sein!? Wie dem auch sei, habe gerade mal sort (coreutils) aus Wheezy getestet und das Ergebnis ist gleich zu Jessie.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Wie kann ich das sortieren?

Beitrag von Meillo » 03.05.2017 14:42:05

tobo hat geschrieben:
Meillo hat geschrieben:Die einzige Regel, die fuer mich Sinn macht, ist das Ignorieren von Tausendertrennern, egal an welchen Stellen sie stehen. (Das ist auch implementatorisch gut umsetzbar ... und damit wahrscheinlich so auch umgesetzt.)
Würden die "vollständig" ignoriert werden, dann sollte doch die Reihenfolge der 101er im printf entscheidend für die Ausgabe sein!?
Nur wenn es ein stabiler Sortieralgorithmus ist, den man bei GNU sort mit `-s' erzwingen kann. Siehe (mit Dezimalkomma):

Code: Alles auswählen

:-Q printf '100,0\n100\n' | LC_ALL=de_DE-UTF-8 sort -n 
100
100,0

:-Q printf '100,0\n100\n' | LC_ALL=de_DE-UTF-8 sort -ns
100,0
100
(Interessant ist, dass mit `-u' immer die ``100,0'' ausgegeben wird, egal ob sie mit oder ohne `-s' die erste oder zweite Zahl war. Das mag vielleicht daran liegen, dass sie eine groessere Genauigkeit bietet ... ach, man sollte man in diesen Quellcode reinschauen, das scheint mir eine ganze Menge schwarzer Magie zu sein ...)
Wie dem auch sei, habe gerade mal sort (coreutils) aus Wheezy getestet und das Ergebnis ist gleich zu Jessie.
Das mag viele Gruende haben. Vielleicht wird intern immer qsort(3) verwendet, das je nach Rechnerarchitektur unterschiedlich implementiert ist ... was weiss ich.

Mit `-s' sollte das Ergebnis aber immer gleich sein, weil dafuer definiert ist, dass gleiche Werte in der Reihenfolge der Eingabe auszugeben sind. Ohne `-s' ist die Reihenfolge in dem Fall implementierungsspezifisch. Soweit die Theorie.
Use ed once in a while!

medias
Beiträge: 90
Registriert: 18.05.2014 11:21:43

Re: Wie kann ich das sortieren?

Beitrag von medias » 04.05.2017 17:38:36

Meillo hat geschrieben: Nein, so:

Code: Alles auswählen

sed 's/\./,/' bsp.txt | LC_NUMERIC="de_DE.UTF-8" sort -t '(' -k1n -k2 | sed 's/,/./'
;-)
Danke für die Hilfe. Ich hatte nicht geahnt das es so schwierig sein würde.

Das mit der 2.100 (in meinem Fall ist das eine Textziffer) ist auch ein Problem wenn ich diese Tabelle nach Excel importiere. Ich weiss noch nicht warum, aber 2.100 wird dabei 2100. ABER 2.99 bleibt 2.99. Sehr dämlich das!

Antworten