GNU сортувати стабільний сортування, коли сортування не знає порядок сортування


18

У мене є файл з двома стовпцями; файл сортується так, як я вже хочу в колонці 1. Я хотів би сортувати в стовпці 2, в межах кожної категорії 1 категорії. Однак sortне розуміє порядок сортування стовпця 1.

Нормальним способом (з подібних питань тут на стеці) було б таке:

sort --stable -k1,1 -k2,2n

Але я не можу вказати сорт на k1, оскільки це довільно.

Приклад введення:

C 2
C 1
A 2
A 1
B 2 
B 1

і вихід:

C 1
C 2
A 1
A 2
B 1 
B 2

Відповіді:


20

Ви можете використовувати awk для початку нового сортування для кожного блоку:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} - коли збережене значення інше, у нас є новий блок, тому ми закриваємо будь-який розпочатий раніше sort
  • {print | "sort -k2,2"}'передає вихід sort, запускаючи його, якщо він ще не працює (awk може відслідковувати команди, які він починає)

2
awk воістину неймовірний. Мені подобається це набагато більше, ніж те, що я очікував, що було дивним прикрасою-сортуванням-неприкосненістю!
Еван Бенн

Я спробував порівняти perf цього та іншу відповідь, не впевнений, чому цей використовує більше ресурсів ... Будь-які ідеї? gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Еван Бенн

Скільки пробіжок ви оцінювали в середньому?
муру

Я не робив усереднення, але спостерігаю послідовний час виконання, коли я повторюю і розслідую.
Еван Бенн

Ось файл, схожий на те, що я використовую, якщо ви хочете розслідувати:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Еван Бенн,

12

Ви можете використовувати трансформацію Шварца (це в основному підхід оформлення-сортування-підкреслення, про який ви згадували в коментарі, але, швидше за все, більш ефективний, ніж точна відповідь Муру через використання одного виклику на відміну від декількох) - використовуючи додавання стовпця з префіксом, який з кроком зі зміною значення в першому стовпчику, відсортуйте за стовпцем префікса, за яким стовпець "другий" (порядкове положення тимчасово перемістилося внаслідок наявності стовпця префікса) і, нарешті, позбудьтесь стовпця префіксаsortawk3

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-

Я здивований, але ви вірні, це було швидше, ніж інша відповідь! 3 хвилини проти 2 хвилин у моєму 100-мільйонному файлі рядків (~ 30 uniq перших стовпців).
Еван Бенн

1
Не потрібно зберігати масив унікального ключа з першого стовпця. Я думаю, що цього повинно вистачити для порівняння першого стовпця поточного рядка з попереднім.
Kusalananda

Щось на кшталт awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(неперевірене).
Kusalananda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.