Numerisch sortieren

7

Ich habe eine Datei namens, dataderen Inhalt sind

id,col1,col2
0,-0.3479417882673812,0.5664382596767175
1,-0.26800930980980764,0.2952025161991604
2,-0.4159790791116641,-1.3375045524610152
3,-0.7859665489205871,-0.6428101880909471
4,-1.3922759043388822,-1.676262144826317
5,-1.2471867496427498,-0.4912119581361516
6,1.443385383041667,1.6974039491263593
7,-2.058899802821969,2.0607628464079917
8,-0.10641338441541626,0.035929568275064216
9,-0.517273684861199,-0.6184800988804992
10,-0.9934859021679552,1.0577312348984502
11,0.5923834706792905,-0.6693757541250825
12,0.8657741917554445,-0.6876271057571398
13,-1.2061097548360489,-0.7402582563022937
14,0.78768021182158,-0.38607117005262315

Das numerische Sortieren ( -n) in der ersten Spalte ergibt

$ sort -nk1 -t"," data
0,-0.3479417882673812,0.5664382596767175
id,col1,col2
1,-0.26800930980980764,0.2952025161991604
2,-0.4159790791116641,-1.3375045524610152
3,-0.7859665489205871,-0.6428101880909471
4,-1.3922759043388822,-1.676262144826317
5,-1.2471867496427498,-0.4912119581361516
7,-2.058899802821969,2.0607628464079917
8,-0.10641338441541626,0.035929568275064216
9,-0.517273684861199,-0.6184800988804992
10,-0.9934859021679552,1.0577312348984502
13,-1.2061097548360489,-0.7402582563022937
6,1.443385383041667,1.6974039491263593
11,0.5923834706792905,-0.6693757541250825
12,0.8657741917554445,-0.6876271057571398
14,0.78768021182158,-0.38607117005262315

Das ist absolut bizarr für mich. Ich habe in der Manpage gelesen, dass -nes sich um eine numerische Sortierung handeln soll. Warum idsollte zwischen Zahlen gesetzt werden? Wie kommt es, dass 10es größer als 9, aber kleiner als die 6ganze Zeit 11größer als sie alle ist?

Das -gscheint zu funktionieren, wie ich will (und wie ich es für natürlich halte), aber diese -nOption entgeht mir völlig. Um was geht's hier? Ich denke, es kann mit dem Gebietsschema zusammenhängen, aber wenn ich das Trennzeichen einmal angegeben ,habe, glaube ich nicht, dass dies das erklären würde.

user347221
quelle

Antworten:

18

TL; DR

Verwenden Sie sort -nk1,1 -t,oder anderweitig, -k1wenn Sie in der vollständigen Zeile sortieren, in der sie ,in Zahlen verworfen werden, da sie als Tausendertrennzeichen interpretiert werden.

Einzelheiten

In englischsprachigen Gebietsschemas ,ist das Tausendertrennzeichen, das sortim ganzzahligen Teil von Zahlen ignoriert wird.

Mit anderen Worten, in einem Gebietsschema in englischer Sprache oder in einem Gebietsschema mit ,tausend Trennzeichen (siehe Ausgabe von locale thousands_sep) wird beim sort -nAnzeigen 11,000,000nicht die 11Nummer gefolgt von einem ignorierten Müll angezeigt, sondern die 11000000Nummer. Ähnlich 11,0ist es 11aber nicht 110.

Definiert nun (und das ist etwas -k1, worauf viele Leute stolpern) einen Schlüssel, der mit dem ersten Feld beginnt, aber da Sie nicht angegeben haben, wo er aufhört, endet er am Ende der Zeile, sodass der Sortierschlüssel die vollständige Zeile ist ist die Standardeinstellung.

Also sort -nk1 -t,ist genau das gleiche wie sort -n.

Mit ,als Tausendertrennzeichen ignoriert, auf Ihre Eingabe sortist die Sortierung tatsächlich diese Zahlen:

0
1
2
3
4
5
61.4433853830416671
7
8
9
10
110.5923834706792905
120.8657741917554445
13
140.78768021182158

So ist es nicht 6vs 10vs 11, sondern 61.4433853830416671vs 10vs 110.5923834706792905.

Hier möchten Sie:

sort -nk1,1 -t,

,Nur nach dem ersten begrenzten Feld sortieren . -k1,1definiert einen Sortierschlüssel, der am Anfang des ersten Feldes beginnt und am Ende des ersten Feldes endet.

Sie können auch sort -ndas Gebietsschema C verwenden, in dem ,weder der Dezimalradius noch das Tausendertrennzeichen (und .der Dezimalradix) angegeben sind:

LC_ALL=C sort -n

sort -gfunktioniert anders, weil sortdann strtold()der Schlüssel als Zahl interpretiert wird und strtold()Tausende von Trennzeichen nicht erkannt werden.

Was die idKopfzeile betrifft, so wird dies in einem numerischen Vergleich id...so interpretiert , dass 0dort keine Zahl zu sehen ist. Es wird nach der Zeile sortiert, mit der begonnen wird, 0da, wenn zwei Datensätze gleich sortiert sind (hier mit -nin einem numerischen Vergleich) sort, ein Last-Resort-Vergleich durchgeführt wird, der ein lexikalischer Vergleich der vollständigen Zeile ist (und 0zuvor sortiert i).

Bei einigen sortImplementierungen kann dieser Vergleich des letzten Auswegs deaktiviert werden -s. Hier LC_ALL=C sort -snwürde die idZeile an erster Stelle stehen, aber das liegt nur daran, dass die Eingabe keine negativen Schlüssel enthält id(die wiederum numerisch 0 ist), nach der noch sortiert wird -1. Wenn Sie die erste Zeile von der Sortierung ausschließen möchten, haben Sie folgende Möglichkeiten:

(head -n1; LC_ALL=C sort -n) < file
Stéphane Chazelas
quelle
Vielen Dank. sort -t, -n -k1,1funktioniert nicht für mich, es platziert 0oben id. Erklärt Ihre Antwort auch, warum sie 10größer als 9, aber kleiner als die 6ganze Zeit 11größer als sie alle ist? Es ist eine echte Frage, die ich selbst nicht beantworten kann, wenn ich Ihre Antwort lese.
user347221
@ user347221, sehen Sie, ob die Bearbeitung es klarer macht.
Stéphane Chazelas
Warum redest du so viel über das Tausendertrennzeichen? Nichts in der Frage deutet darauf hin, dass sie erwartet haben, dass es Teil der Zahl ist. Sie müssen -t","es als Feldtrennzeichen verwenden.
Barmar
Wo ist 61.4433853830416671in der Eingabedatei? Ich verstehe 6,1.443385383041667,1.6974039491263593.
Barmar
1
@ StéphaneChazelas Danke, das ist großartig. unix.SE ist Äonen jenseits anderer SE-Sites. Die Leute helfen hier tatsächlich. Ich habe mit vielen Benutzern hier großartige Erfahrungen gemacht. Gilles, Kusalananda, Stephen, Terdon, um nur einige zu nennen. Danke euch allen.
user347221