Сортировка по последнему столбцу (или любому другому столбцу с числовым значением )CSV-файла

Ваш образец ввода перепутан -1-я строка (заголовки столбцов )даже не имеют запятых-разделителей полей -и в большинстве строк нет запятой между полями фамилии и оценки.

Чтобы обеспечить несколько -разумный ввод, я отредактировал его, чтобы он выглядел следующим образом:

$ cat input.txt 
ID, uid ,firstname,lastname,   grade   , country n28
1, ed23, jon    ,   doe  ,  director ,  usa
2, ed23,  jon    ,  doe  ,  director    , usa
3, er67,  jake    , Kogan,  director    , usa
4, er67,  jake    , Kogan,  director    , usa
5, dc10,  Charls    ,Morg,  manager     , usa
6, kc56,  patel    ,Kumar,  associate   , india

Простая реализация, просто исключающая дубликаты, будет примерно такой:

$ awk -F' *, *' -v OFS=, \
    'NR==1 {$1=$1;$0=$0; print; next};
     {id=$1; $1=""; $0=$0; if (!seen[$0]++) {print id $0}}' input.txt 
ID,uid,firstname,lastname,grade,country n28
1,ed23,jon,doe,director,usa
3,er67,jake,Kogan,director,usa
5,dc10,Charls,Morg,manager,usa
6,kc56,patel,Kumar,associate,india

Это устанавливает разделитель полей ввода(FS)равным нулю -или -больше пробелов, за которыми следует запятая, затем ноль -или -больше пробелов, а разделитель полей вывода(OFS)просто запятая. то есть он эффективно удаляет начальные и конечные пробелы из всех полей.

Для первой строки ввода(NR==1)используется awk-трюк для переформатирования строки ввода :, изменения любого из полей (, даже установки исходного значения ), а затем установки $0=$0. Линия будет переформатирована для использования нового OFS. затем он печатает его и переходит к следующей строке.

Для остальных входных данных он сохраняет $1 в переменной с именем id, устанавливает $1 в пустую строку, а затем снова использует трюк $0=$0(, эффективно удаляя $1 из строки )перед печатью идентификатора. и остаток строки.

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

Чтобы сделать обе эти вещи, требуется прочитать весь входной файл перед созданием любого вывода, а также второй массив(ids)для отслеживания последних -увиденных идентификационных номеров дубликатов -, использующих в два раза больше памяти., что может быть значительным при 700 тыс. входных строк.

$ awk -F' *, *' -v OFS=, \
   'NR==1 {$1=$1;$0=$0",count";print;next};
   {id=$1; $1=""; $0=$0; seen[$0]++; ids[$0]=id};
   END { for (id in ids) {print ids[id] id, seen[id]} }' input.txt  | \
 sort -n
ID,uid,firstname,lastname,grade,country n28,count
2,ed23,jon,doe,director,usa,2
4,er67,jake,Kogan,director,usa,2
5,dc10,Charls,Morg,manager,usa,1
6,kc56,patel,Kumar,associate,india,1

sort -nиспользуется здесь, потому что ассоциативные массивы в awk неупорядочены, поэтому появляются в полу-случайном порядке. В GNU awk есть функция asort(), которая может сортировать массивы по значению, которое можно было бы использовать в массиве idsздесь, но )она не переносима, и b )ее легко передать по конвейеру в sort -n.

1
21.09.2021, 19:05
1 ответ

Если вы знаете, сколько у вас полей:

$ sort -t, -k7,7n file
XYZ,JKL,MNO,3,-5,0.2,-0.342
STU,WXY,DEF,-1,4,0.01,0.345
ABC,DEF,GHI,-5,-8,-0.6,0.488

или если нет:

$ awk 'BEGIN{FS=OFS=","} {print $NF,$0}' file | sort -t, -k1,1n | cut -d, -f2-
XYZ,JKL,MNO,3,-5,0.2,-0.342
STU,WXY,DEF,-1,4,0.01,0.345
ABC,DEF,GHI,-5,-8,-0.6,0.488

и сортировать по 3-му -последнему вместо последнего поля, очевидно, будет просто:

$ awk 'BEGIN{FS=OFS=","} {print $(NF-2),$0}' file | sort -t, -k1,1n | cut -d, -f2-
ABC,DEF,GHI,-5,-8,-0.6,0.488
XYZ,JKL,MNO,3,-5,0.2,-0.342
STU,WXY,DEF,-1,4,0.01,0.345

Если вы хотите сохранить порядок ввода, когда несколько строк имеют одинаковое значение для поля, по которому вы сортируете, то, если у вас есть сортировка GNU, вы можете использовать -s, в противном случае включите номер строки в качестве вторичного ключа сортировки:

$ awk 'BEGIN{FS=OFS=","} {print $NF,NR,$0}' file | sort -t, -k1,1n -k2,2n | cut -d, -f3-
XYZ,JKL,MNO,3,-5,0.2,-0.342
STU,WXY,DEF,-1,4,0.01,0.345
ABC,DEF,GHI,-5,-8,-0.6,0.488
1
22.09.2021, 13:55

Теги

Похожие вопросы