В чем разница между параметрами --general-numeric-sort и --numeric-sort в gnu sort

113

sortпредоставляет два вида числовой сортировки. Это со страницы руководства:

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

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

Какая разница?

Трентон
источник
17
Обратите внимание, что полная документация sortне на manстранице, а на infoстранице ( info sort).
a3nm

Ответы:

85

Общая числовая сортировка сравнивает числа как числа с плавающей запятой, это позволяет использовать научную нотацию, например, 1.234E10, но работает медленнее и подвержена ошибкам округления (1.2345678 может идти после 1.2345679), числовая сортировка - это обычная буквенная сортировка, которая знает, что 10 идет после 9.

См. Http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html

'-g' '--general-numeric-sort' '--sort = general-numeric' Произвести числовую сортировку с использованием стандартной функции C strtod для преобразования префикса каждой строки в число с плавающей запятой двойной точности. Это позволяет указывать числа с плавающей запятой в экспоненциальной нотации, например 1.0e-34 и 10e100. Локаль LC_NUMERIC определяет символ десятичной точки. Не сообщайте об ошибках переполнения, недополнения или преобразования. Используйте следующую последовательность сортировки: строки, которые не начинаются с цифр (все считаются равными). NaN (значения «не числа» в арифметике с плавающей запятой IEEE) в согласованном, но машинно-зависимом порядке. Минус бесконечность. Конечные числа в возрастающем числовом порядке (с равными -0 и +0). Плюс бесконечность.

Используйте эту опцию, только если нет альтернативы; он намного медленнее, чем --numeric-sort (-n), и может потерять информацию при преобразовании в числа с плавающей запятой.

'-n' '--numeric-sort' '--sort = numeric' Сортировка в числовом виде. Число начинается с каждой строки и состоит из необязательных пробелов, необязательного знака «-» и нуля или более цифр, которые могут быть разделены разделителями тысяч, за которыми необязательно следует десятичный знак и ноль или более цифр. Пустое число рассматривается как «0». Локаль LC_NUMERIC определяет десятичную точку и разделитель тысяч. По умолчанию пробел - это пробел или табуляция, но языковой стандарт LC_CTYPE может это изменить.

Сравнение точное; ошибки округления нет.

Ни ведущий знак "+", ни экспоненциальное обозначение не распознаются. Чтобы сравнить такие строки численно, используйте параметр --general-numeric-sort (-g).

Мартин Беккет
источник
2
Спасибо. Странно, что на страницах man и info этого нет. Я также не знал о gnu.org/software/coreutils/manual/html_node/index.html .
Трентон,
6
У меня это не работает. Я сортирую файл с третьим столбцом с содержанием вроде R1 R2 R10 R15. Используя или -k3.2nили -k3.2g, он выполняет сортировку R10раньше R2. Сортировка лексикографическая, а не числовая. Я ожидаю, что он будет рассматривать поле, начиная со второго символа, как число.
Kaz
6
@Kaz: sortключевые характеристики. действительно византийские - вкратце: пробелы перед полем считаются частью поля , поэтому char. index 1 указывает на (первый) пробел перед полем, а не на фактический первый символ поля. Добавьте суффикс к символу. index с помощью, bчтобы исправить эту проблему, то есть: -k 3.2bn,3(обратите внимание, что глобальная -b опция в этом случае не работает). Также обратите внимание на добавленное ,3, которое гарантирует, что используется только 3-е поле - без этого индекса 2-го поля используется остаток от всей строки .
mklement0
11

Вы должны быть осторожны с вашим регионом. Например, вы можете намереваться отсортировать плавающее число (например, 2.2), тогда как в вашем языковом стандарте может ожидаться использование запятой (например, 2,2).

Как сообщается на этом форуме , вы можете получить неверные результаты, используя флаги -n или -g.

В моем случае я использую:

LC_ALL=C sort -k 6,6n file

для сортировки 6-го столбца, который содержит:

2.5
3.7
1.4

чтобы получить

1.4
2.5
3.7
JFL
источник
2
Даже с LANG = C я не могу -nраспознать запятую как разделитель тысяч - «1000» обрабатывается так же, как «1».
Скотт
1
Это должно быть LC_ALL = C.
Стюарт П. Бентли
@Scott: Действительно, разделители тысяч НЕ распознаются: sortиспользуется логика самого длинного префикса : используется самая длинная часть строки / ключа, которую он распознает как число; в языковом стандарте, который используется .в качестве символа основания, он перестанет читать на ,.
mklement0 03
@ StuartP.Bentley: LC_ALL=Cэто действительно самый надежный выбор; однако, если LC_ALLставка не установлена, LANG=Cтоже сработает.
mklement0 03
1
Хороший момент, но LANG=C sort -k 6,6n fileон и проще, и локализует эффект установки переменной среды LANGдля конкретной команды.
mklement0 03
0

В дополнение к принятому ответу, в котором упоминается -gразрешение научных обозначений , я хочу показать ту часть, которая, скорее всего, вызывает нежелательное поведение.

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

Обратите внимание на zooтри важных момента:

  • Строка начинается с NAN(например, Nanaи nani lol) или -INF(одиночное тире, не --INF) перемещается в конец, но перед цифрами. Пока INFпереходите к последней цифре после цифр, потому что это означает бесконечность .

  • NAN, INFИ -INFэто чувствительно к регистру .

  • Линии всегда игнорируют пробелы с обеих сторон NAN, INF, -INF (независимо от LC_CTYPE). Другой алфавит может игнорировать пробелы с любой стороны в зависимости от языкового стандарта LC_COLLATE(например, LC_COLLATE=fr_FR.UTF-8игнорировать, но LC_COLLATE=us_EN.UTF-8не игнорировать).

Поэтому, если вы сортируете произвольные буквенно-цифровые символы, вам, вероятно, не нужно -g. Если вам действительно нужно сравнение с научной нотацией -g, то вы, вероятно, захотите извлечь алфавитные и числовые данные и провести сравнение отдельно .

Если вам нужна только обычная 1, -1сортировка чисел (например ) и вы чувствуете, что это 0x/E/+ sortingне важно, просто используйте -nдостаточно:

$ 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

Либо из, -gлибо -n, имейте в виду эффект локали . Вы можете указать LC_NUMERICas, us_EN.UTF-8 чтобы избежать сбоя сортировки fr_FR.UTF-8 -с плавающим числом :

$ 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

С 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

Или LC_NUMERIC=us_EN.UTF-8сгруппировать +|-|spaceс 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

Вы, вероятно, захотите указать localeпри использовании sort, хотите ли вы писать переносимый скрипт.

Фрукты
источник