Qual é a diferença entre as opções --general-numeric-sort e --numeric-sort no gnu sort

113

sortfornece dois tipos de classificação numérica. Isto é da página de manual:

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

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

Qual é a diferença?

Trenton
fonte
17
Observe que a documentação completa do sortnão é a manpágina, mas a infopágina ( info sort).
A3nm

Respostas:

85

A classificação numérica geral compara os números como flutuantes, isso permite a notação científica, por exemplo, 1.234E10, mas é mais lenta e sujeita a erros de arredondamento (1.2345678 pode vir depois de 1.2345679), a classificação numérica é apenas uma classificação alfabética regular que sabe que 10 vem depois de 9.

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

'-g' '--general-numeric-sort' '--sort = general-numeric' Classifica numericamente, usando a função C padrão strtod para converter um prefixo de cada linha em um número de ponto flutuante de precisão dupla. Isso permite que números de ponto flutuante sejam especificados em notação científica, como 1.0e-34 e 10e100. O local LC_NUMERIC determina o caractere de ponto decimal. Não relate estouro, estouro negativo ou erros de conversão. Use a seguinte sequência de intercalação: Linhas que não começam com números (todas consideradas iguais). NaNs (valores “Não é um número”, em aritmética de ponto flutuante IEEE) em uma ordem consistente, mas dependente da máquina. Menos infinito. Números finitos em ordem numérica crescente (com -0 e +0 iguais). Além do infinito.

Use esta opção apenas se não houver alternativa; é muito mais lento do que --numeric-sort (-n) e pode perder informações ao converter para ponto flutuante.

'-n' '--numeric-sort' '--sort = numeric' Classifica numericamente. O número começa cada linha e consiste em espaços em branco opcionais, um sinal '-' opcional e zero ou mais dígitos possivelmente separados por separadores de milhares, opcionalmente seguidos por um caractere de ponto decimal e zero ou mais dígitos. Um número vazio é tratado como '0'. O local LC_NUMERIC especifica o caractere de ponto decimal e separador de milhares. Por padrão, um espaço em branco é um espaço ou uma guia, mas o local LC_CTYPE pode alterar isso.

A comparação é exata; não há erro de arredondamento.

Nem um '+' inicial nem notação exponencial é reconhecida. Para comparar tais strings numericamente, use a opção --general-numeric-sort (-g).

Martin Beckett
fonte
2
Obrigado. Estranho que as páginas man e info não tenham isso nelas. Eu também não sabia sobre gnu.org/software/coreutils/manual/html_node/index.html .
Trenton
6
Essas coisas não estão funcionando para mim. Estou classificando um arquivo com uma terceira coluna com conteúdo como R1 R2 R10 R15. Usando -k3.2nou -k3.2g, ele está classificando R10antes R2. A classificação é lexicográfica, não numérica. Espero que ele trate o campo do segundo caractere em diante como um número.
Kaz
6
@Kaz: sortas principais especificações. são verdadeiramente bizantinos - resumindo, os espaços em branco que precedem o campo são considerados parte do campo , então char. o índice 1 aponta para o (primeiro) espaço em branco que precede o campo, não o primeiro caractere real do campo. Sufixe o char. index com bpara corrigir este problema, ou seja: -k 3.2bn,3(observe que a opção global não funciona neste caso). Observe também o adicionado , que garante que apenas o 3º campo seja usado - sem esse 2º campo índice, o restante da linha inteira é usado. -b,3
mklement0 01 de
11

Você deve ter cuidado com sua localidade. Por exemplo, você pode querer classificar um número flutuante (como 2.2) enquanto sua localidade pode esperar o uso de uma vírgula (como 2,2).

Conforme relatado neste fórum , você pode ter resultados errados usando os sinalizadores -n ou -g.

No meu caso eu uso:

LC_ALL=C sort -k 6,6n file

para classificar a 6ª coluna que contém:

2.5
3.7
1.4

com o propósito de obter

1.4
2.5
3.7
JFL
fonte
2
Mesmo com LANG = C, não consigo -nreconhecer a vírgula como um separador de milhares - “1.000” é tratado da mesma forma que “1”.
Scott
1
Isso deve ser LC_ALL = C.
Stuart P. Bentley,
@Scott: Na verdade, separadores de milhares NÃO são reconhecidos: sortusa a lógica do prefixo mais longo: a parte mais longa da linha / chave que ele reconhece como um número é usada; em um local que usa .como caractere raiz, a leitura será interrompida em ,.
mklement0
@ StuartP.Bentley: LC_ALL=Cé de fato a escolha mais robusta ; entretanto, se LC_ALLacontecer de não apostar definido, LANG=Cfuncionará também.
mklement0
1
Bom ponto, mas LANG=C sort -k 6,6n fileé mais simples e também localiza o efeito de definir a variável de ambiente LANGpara o comando específico.
mklement0
0

Além da resposta aceita cuja menção -gpermite a notação científica , quero mostrar a parte que mais provavelmente causa um comportamento indesejável.

Com -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

Veja as zootrês coisas importantes aqui:

  • A linha começa com NAN(por exemplo, Nanae nani lol) ou -INF(um traço, não --INF) move para o fim, mas antes dos dígitos. Enquanto INFmove para o último após os dígitos, porque significa infinito .

  • O NAN, INFe -INFnão diferenciam maiúsculas de minúsculas .

  • As linhas sempre ignorar espaço em branco a partir de ambos os lados de NAN, INF, -INF (independentemente LC_CTYPE). Outros alfabéticos podem ignorar os espaços em branco de qualquer lado, dependendo do local LC_COLLATE(por exemplo, LC_COLLATE=fr_FR.UTF-8ignorar, mas LC_COLLATE=us_EN.UTF-8não ignorar).

Portanto, se você está classificando alfanuméricos arbitrários , provavelmente não deseja -g. Se você realmente precisa de comparação de notação científica com -g, provavelmente deseja extrair dados alfabéticos e numéricos e fazer a comparação separadamente .

Se você precisa apenas de 1, -1classificação por número comum (por exemplo ), e acha que isso 0x/E/+ sortingnão é importante, use apenas o -nsuficiente:

$ 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

Ou -gou -n, esteja ciente do efeito local . Você pode querer especificar LC_NUMERICcomo us_EN.UTF-8 evitar falha na classificação fr_FR.UTF-8 -com número flutuante :

$ 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

Com 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

Ou LC_NUMERIC=us_EN.UTF-8para agrupar +|-|spacecom 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

Você provavelmente deseja especificar localequando usar sortse deseja escrever um script portátil.

Fruta
fonte