Jaka jest różnica między opcjami --general-numeric-sort i --numeric-sort w gnu sort

113

sortudostępnia dwa rodzaje sortowania numerycznego. To jest ze strony podręcznika:

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

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

Co za różnica?

Trenton
źródło
17
Zauważ, że pełna dokumentacja sortnie jest manstroną, ale infopage ( info sort).
a3nm

Odpowiedzi:

85

Ogólne sortowanie numeryczne porównuje liczby jako zmiennoprzecinkowe, co pozwala na notację naukową, np. 1.234E10, ale jest wolniejsze i obarczone błędem zaokrąglenia (1.2345678 może nastąpić po 1.2345679), sortowanie numeryczne jest zwykłym sortowaniem alfabetycznym, w którym 10 występuje po 9.

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

'-g' '--general-numeric-sort' '--sort = general-numeric' Sortuj numerycznie, używając standardowej funkcji C strtod do konwersji przedrostka każdego wiersza na liczbę zmiennoprzecinkową o podwójnej precyzji. Pozwala to na podawanie liczb zmiennoprzecinkowych w notacji naukowej, na przykład 1.0e-34 i 10e100. Ustawienia regionalne LC_NUMERIC określają znak przecinka dziesiętnego. Nie zgłaszaj błędów przepełnienia, niedomiaru ani konwersji. Użyj następującej kolejności zestawiania: Wiersze, które nie zaczynają się od liczb (wszystkie są uważane za równe). NaNs (wartości „Not a Number”, w arytmetyce zmiennoprzecinkowej IEEE) w spójnej, ale zależnej od maszyny kolejności. Minus nieskończoność. Liczby skończone w rosnącym porządku liczbowym (przy równych -0 i +0). Plus nieskończoność.

Użyj tej opcji tylko wtedy, gdy nie ma alternatywy; jest znacznie wolniejszy niż --numeric-sort (-n) i może utracić informacje podczas konwersji na zmiennoprzecinkowe.

'-n' '--numeric-sort' '--sort = numeric' Sortuj numerycznie. Liczba zaczyna się w każdym wierszu i składa się z opcjonalnych odstępów, opcjonalnego znaku „-” oraz zera lub większej liczby cyfr, które mogą być oddzielone separatorami tysięcy, po których opcjonalnie następuje znak przecinka oraz zero lub więcej cyfr. Pusta liczba jest traktowana jako „0”. Ustawienia regionalne LC_NUMERIC określają znak przecinka dziesiętnego i separator tysięcy. Domyślnie puste miejsce to spacja lub tabulator, ale ustawienia narodowe LC_CTYPE mogą to zmienić.

Porównanie jest dokładne; nie ma błędu zaokrąglenia.

Nie jest rozpoznawany ani wiodący znak „+”, ani notacja wykładnicza. Aby porównać takie ciągi liczbowo, użyj opcji --general-numeric-sort (-g).

Martin Beckett
źródło
2
Dzięki. Dziwne, że strony man i info nie mają tego w sobie. Nie wiedziałem też o gnu.org/software/coreutils/manual/html_node/index.html .
Trenton
6
To nie działa dla mnie. Sortuję plik z trzecią kolumną o zawartości typu R1 R2 R10 R15. Używając albo -k3.2nlub -k3.2g, jest to sortowanie R10przed R2. Sortowanie jest leksykograficzne, a nie numeryczne. Spodziewam się, że potraktuje pole od drugiego znaku jako liczbę.
Kaz,
6
@Kaz: sortkluczowe specyfikacje. są prawdziwie bizantyjskie - w skrócie: puste miejsce (a) poprzedzające pole są uważane za część pola , więc char. indeks 1 wskazuje na (pierwszy) odstęp poprzedzający pole, a nie rzeczywisty pierwszy znak pola. Dodaj przyrostek char. index z, baby rozwiązać ten problem, tj .: -k 3.2bn,3(zwróć uwagę, że opcja globalna nie działa w tym przypadku). Zwróć również uwagę na dodanie , które zapewnia, że ​​używane jest tylko trzecie pole - bez tego indeksu drugiego pola używana jest reszta całej linii . -b,3
mklement0
11

Powinieneś uważać na swoje ustawienia regionalne. Na przykład, możesz chcieć posortować liczbę zmiennoprzecinkową (jak 2.2), podczas gdy twoje ustawienia narodowe mogą oczekiwać użycia przecinka (jak 2,2).

Jak informowaliśmy na tym forum , możesz mieć błędne wyniki używając flag -n lub -g.

W moim przypadku używam:

LC_ALL=C sort -k 6,6n file

aby posortować szóstą kolumnę zawierającą:

2.5
3.7
1.4

w celu uzyskania

1.4
2.5
3.7
JFL
źródło
2
Nawet przy LANG = C nie mogę -nrozpoznać przecinka jako separatora tysięcy - „1000” jest traktowane tak samo jak „1”.
Scott
1
To powinno być LC_ALL = C.
Stuart P. Bentley
@Scott: Rzeczywiście, separatory tysięcy NIE są rozpoznawane: sortużywa logiki najdłuższego prefiksu : używana jest najdłuższa część wiersza / klucza, który rozpoznaje jako liczbę; w ustawieniach regionalnych używających .znaku radix przestanie czytać o ,.
mklement0
@ StuartP.Bentley: LC_ALL=Cto rzeczywiście najbardziej solidny wybór; jeśli jednak LC_ALLzdarzy się , że nie postawisz seta, LANG=Czadziała też.
mklement0
1
Dobra uwaga, ale LANG=C sort -k 6,6n filejest zarówno prostsza, jak i lokalizuje wpływ ustawienia zmiennej środowiskowej LANGna określone polecenie.
mklement0
0

Oprócz zaakceptowanej odpowiedzi, w której wspomina się o -gdopuszczeniu notacji naukowej , chcę pokazać część, która najprawdopodobniej powoduje niepożądane zachowanie.

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

Spójrz na zootrzy ważne rzeczy:

  • Linia zaczyna się od NAN(np. NanaI nani lol) lub -INF(pojedynczy myślnik, nie --INF) i kończy się, ale przed cyframi. A INFprzejdź do ostatniego po cyfrach, ponieważ oznacza to nieskończoność .

  • NAN, INFI -INFwrażliwe na wielkość liter .

  • Linie zawsze ignorować spacje po obu stronach NAN, INF, -INF (niezależnie od LC_CTYPE). Inne alfabetyczne mogą ignorować białe znaki z obu stron, w zależności od ustawień regionalnych LC_COLLATE(np. LC_COLLATE=fr_FR.UTF-8Ignoruj, ale LC_COLLATE=us_EN.UTF-8nie ignoruj).

Więc jeśli sortujesz dowolne alfanumeryczne , prawdopodobnie nie chcesz -g. Jeśli naprawdę potrzebujesz porównania notacji naukowej z -g, prawdopodobnie chcesz wyodrębnić dane alfabetyczne i liczbowe i zrobić porównanie oddzielnie .

Jeśli potrzebujesz tylko zwykłego 1, -1sortowania liczb (np. ) I uważasz, że 0x/E/+ sortingnie jest to ważne, po prostu użyj -nwystarczającej ilości:

$ 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

Albo -gbądź -nświadomy efektu lokalnego . Możesz chcieć określić LC_NUMERICjako, us_EN.UTF-8 aby uniknąć fr_FR.UTF-8 sortowanie -z liczbą zmiennoprzecinkową nie powiodło się :

$ 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

Z 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

Lub LC_NUMERIC=us_EN.UTF-8w grupie +|-|spacez 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

Prawdopodobnie chcesz określić, localekiedy używasz, sortjeśli chcesz napisać przenośny skrypt.

Owoc
źródło