Qual è la differenza tra le opzioni --general-numeric-sort e --numeric-sort in gnu sort


113

sortfornisce due tipi di ordinamento numerico. Questo è dalla pagina man:

   -g, --general-numeric-sort
          compare according to general numerical value

   -n, --numeric-sort
          compare according to string numerical value

Qual è la differenza?


17
Nota che la documentazione completa di sortnon è la manpagina ma la infopagina ( info sort).
A3nm

Risposte:


85

L'ordinamento numerico generale confronta i numeri come float, ciò consente la notazione scientifica ad es. 1.234E10 ma è più lento e soggetto a errori di arrotondamento (1.2345678 potrebbe venire dopo 1.2345679), l'ordinamento numerico è solo un ordinamento alfabetico regolare che sa che 10 viene dopo 9.

Vedi http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html

'-g' '--general-numeric-sort' '--sort = general-numeric' Ordina numericamente, utilizzando la funzione C standard strtod per convertire un prefisso di ogni riga in un numero a virgola mobile a precisione doppia. Ciò consente di specificare i numeri in virgola mobile nella notazione scientifica, come 1.0e-34 e 10e100. La locale LC_NUMERIC determina il carattere del punto decimale. Non segnalare errori di overflow, underflow o di conversione. Utilizzare la seguente sequenza di confronto: Righe che non iniziano con numeri (considerate tutte uguali). NaN (valori "Not a Number", in aritmetica a virgola mobile IEEE) in un ordine coerente ma dipendente dalla macchina. Meno infinito. Numeri finiti in ordine numerico crescente (con -0 e +0 uguali). Più infinito.

Usa questa opzione solo se non ci sono alternative; è molto più lento di --numeric-sort (-n) e può perdere informazioni durante la conversione in virgola mobile.

'-n' '--numeric-sort' '--sort = numeric' Ordina numericamente. Il numero inizia ogni riga ed è composto da spazi vuoti opzionali, un segno "-" opzionale e zero o più cifre eventualmente separate da separatori delle migliaia, eventualmente seguite da un carattere punto decimale e zero o più cifre. Un numero vuoto viene considerato come "0". La locale LC_NUMERIC specifica il carattere del punto decimale e il separatore delle migliaia. Per impostazione predefinita, uno spazio vuoto è uno spazio o una tabulazione, ma le impostazioni internazionali LC_CTYPE possono modificarlo.

Il confronto è esatto; non ci sono errori di arrotondamento.

Non viene riconosciuta una notazione "+" iniziale né esponenziale. Per confrontare tali stringhe numericamente, usa l'opzione --general-numeric-sort (-g).


2
Grazie. Strano che le pagine man e info non contengano questo. Inoltre non sapevo di gnu.org/software/coreutils/manual/html_node/index.html .
Trenton

6
Questa roba non funziona per me. Sto ordinando un file con una terza colonna con contenuti come R1 R2 R10 R15. Usando uno -k3.2no l'altro -k3.2g, sta ordinando R10prima R2. L'ordinamento è lessicografico, non numerico. Mi aspetto che tratti il ​​campo dal secondo carattere in poi come un numero.
Kaz

6
@Kaz: sortle specifiche chiave di. sono veramente bizantini - il corto è: gli spazi che precedono il campo sono considerati parte del campo , quindi il carattere. l'indice 1 punta al (primo) spazio che precede il campo, non al primo carattere effettivo del campo. Aggiungi il suffisso al carattere. index con bper risolvere questo problema, ovvero: -k 3.2bn,3(nota che l' opzione globale non funziona in questo caso). Notare anche l'aggiunta , che garantisce che venga utilizzato solo il 3 ° campo - senza quel 2 ° indice di campo, viene utilizzato il resto dell'intera riga . -b,3
mklement0

11

Dovresti stare attento con la tua localizzazione. Ad esempio, potresti voler ordinare un numero mobile (come 2.2) mentre la tua locale potrebbe aspettarsi l'uso di una virgola (come 2.2).

Come riportato in questo forum , potresti avere risultati errati usando i flag -n o -g.

Nel mio caso utilizzo:

LC_ALL=C sort -k 6,6n file

per ordinare la sesta colonna che contiene:

2.5
3.7
1.4

per ottenere

1.4
2.5
3.7

2
Anche con LANG = C, non riesco -na riconoscere la virgola come separatore delle migliaia: "1.000" viene considerato come "1".
Scott

1
Dovrebbe essere LC_ALL = C.
Stuart P. Bentley

@Scott: In effetti, i separatori delle migliaia NON sono riconosciuti: sortutilizza la logica del prefisso più lungo : viene utilizzata la parte più lunga della linea / chiave che riconosce come numero; in una lingua che utilizza .come carattere radice, smetterà di leggere alle ,.
mklement0

@ StuartP.Bentley: LC_ALL=Cè davvero la scelta più robusta ; tuttavia, se LC_ALLcapita di non puntare impostato, LANG=Cfunzionerà anche.
mklement0

1
Buon punto, ma LANG=C sort -k 6,6n fileè sia più semplice che localizza anche l'effetto dell'impostazione della variabile di ambiente LANGsul comando specifico.
mklement0

0

Oltre alla risposta accettata la cui menzione -gconsente la notazione scientifica , voglio mostrare la parte che molto probabilmente causa un comportamento indesiderato.

Con -g:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -g myfile
baa
--inf
--inf  
--inf- 
--inf--
--inf-a
--nnf
nnf--
   nnn  
tnan
zoo
   naN
Nana
nani lol
-inf
-inf--
-11
-2
-1
1
+1
2
+2
0xa
11
+11
inf

Guarda le zootre cose importanti qui:

  • La riga inizia con NAN(ad esempio Nanae nani lol) o -INF(trattino singolo, non --INF) si sposta alla fine ma prima delle cifre. Mentre INFspostati all'ultimo dopo le cifre perché significa infinito .

  • Il NAN, INFe -INFsono case insensitive .

  • Le linee ignorano sempre spazi da entrambi i lati NAN, INF, -INF (indipendentemente LC_CTYPE). Altri alfabetici possono ignorare gli spazi da entrambi i lati a seconda delle impostazioni locali LC_COLLATE(ad esempio, LC_COLLATE=fr_FR.UTF-8ignora ma LC_COLLATE=us_EN.UTF-8non ignora).

Quindi, se stai ordinando alfanumerico arbitrario , probabilmente non lo vuoi -g. Se hai davvero bisogno del confronto della notazione scientifica con -g, allora probabilmente vuoi estrarre i dati alfabetici e numerici e fare il confronto separatamente .

Se hai solo bisogno dell'ordinamento ordinario dei numeri (ad es. 1, -1) E ritieni che 0x/E/+ sortingnon sia importante, usane -nabbastanza:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -n myfile
-1000
-22
-13
-11
-010
-10
-5
-2
-1
-0.2
-0.12
-0.11
-0.1
0x1
0x11
0xb
+1
+11
+2
-a
-aa
--aa
-aaa
-b
baa
BAA
bbb
+ignore
inf
-inf
--inf
--inf  
--inf- 
--inf--
-inf--
--inf-a
   naN
Nana
nani lol
--nnf
nnf--
   nnn  
None         
uum
Zero cool
-zzz
1
1.1
1.234E10
5
11

Uno di -go -n, essere consapevoli dell'effetto locale . Puoi specificare LC_NUMERICcome us_EN.UTF-8 evitare l'ordinamento fr_FR.UTF-8 -con numero mobile non riuscito :

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=fr_FR.UTF-8 sort -n myfile
-10
-5
-2
-1
-1.1
-1.2
-0.1
-0.11
-0.12
-0.2
-a
+b
middle
-wwe
+zoo
1
1.1

Con LC_NUMERIC=en_US.UTF-8:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=en_US.UTF-8 sort -n myfile
-10
-5
-2
-1.2
-1.1
-1
-0.2
-0.12
-0.11
-0.1
-a
+b
middle
-wwe
+zoo
1
1.1

O LC_NUMERIC=us_EN.UTF-8 per un gruppo +|-|spacecon alpha:

$ LC_COLLATE=fr_FR.UTF-8 LC_NUMERIC=us_EN.UTF-8 sort -n myfile
-0.1
    a
    b
 a
 b
+b
+zoo
-a
-wwe
middle
1

Probabilmente vuoi specificare localequando usisort se si desidera scrivere uno script portatile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.