Сортировка блоков строк


12

У меня есть файл, который содержит 4n строк. Вот выдержка из него, содержащая 8 строк

6115 8.88443
6116 6.61875
6118 16.5949
6117 19.4129
6116 6.619 
6117 16.5979 
6118 19.4111
6115 8.88433  

То, что я хочу сделать, это отсортировать блок, где каждый блок состоит из 4 строк на основе первого столбца. Вывод выдержки должен выглядеть так, как показано ниже.

6115 8.88443
6116 6.61875
6117 19.4129
6118 16.5949
6115 8.88433 
6116 6.619 
6117 16.5979 
6118 19.4111 

Ответы:


16

Одним из вариантов является использование для добавления начального префикса серийного номера через каждые N строк (N = 4 в вашем случае). Затем введите префикс в качестве основного столбца сортировки sort.

Пример с N = 4:

awk '{print int((NR-1)/4), $0}' file.txt | sort -n -k1,1 -k2,2 | cut -f2- -d' '

7

Если это не так, и вы не хотите изучать python, perl или awk, вы можете пойти с основными splitи sortкомандами.

Сначала разбейте файл на 4 строки с -l опцией:

split -a 6 -l 4 input_file my_prefix_
for fn in my_prefix_*; do
    sort -n -o $fn $fn
done
cat my_prefix_* > output_file
rm my_prefix_*

Эти sort -nвиды по числовому значению первого столбца (999) перед тем 1234. -a 6должен заботиться о файле с 26 ^ 6 * 4 строки. my_prefix_должно быть что-то уникальное для каталога, с которым вы работаете.


3

Вы можете сделать это с Perl:

perl -nle '
   push @a,$_;
   unless($. % 4){
       print join "\n",sort {$a <=> $b} @a; # Sort @a, and print its contents
       @a = (); # Empty @a to start a new block
   }
' your_file

Как это работает

  • -n-> запустить код для каждой строки ввода (и поместить текущую строку в $_)
  • -l -> добавить новую строку к выводу любого print
  • -e -> выполнить следующую строку как код Perl
  • Каждая строка добавляется в массив @a.
  • $.содержит текущий номер строки и, если это число не совпадает с нулем по модулю 4, то мы продолжаем работать. Если он равен нулю по модулю 4, мы достигли строки, число которой кратно 4 (конец блока), и в этом случае мы сортируем записи @aв порядке возрастания номеров и печатаем записи в отсортированном массиве. добавлен перевод строки в стандартный вывод.

2

Используя Bourne-подобную оболочку,

while read a ; do                                           # Try reading a line.
    read b ; read c ; read d                                # OK, read 3 more.
    printf '%s\n%s\n%s\n%s\n' "$a" "$b" "$c" "$d" | sort -n # Sort them.
done < data

2

Вот несколько «чистых» awkрешений:

Если индексы всегда имеют ту же последовательность приращения целых чисел (6115-6119), что и в ваших данных выборки, вы можете использовать алгоритмический «ярлык»:

awk '{a[$1]=$0} !(NR%4){for(i=6115;i<6119;print a[i++]);}'

Это делает

  • Добавьте все строки в массив a, распределенные по позициям индекса 6115-6119
  • В каждой 4-й строке ( !(NR%4)) просматривайте содержимое массива для печати в нужном порядке.

Если ваши числовые индексы всегда являются четырьмя одинаковыми, но не последовательностью целочисленного увеличения, вам придется выполнить сортировку:

awk '{a[$1]=$0} !(NR%4){asort(a,b); for(i=1;i<5;print b[i++]);}'

Примечание: это с GNU awk, другие могут не поддерживать asort.


Если каждый блок из четырех может иметь разные числовые идентификаторы:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;print a[i++]); delete a}'

Примечание: TIL от @Gilles self-answer (+2) это использование deleteне (пока) POSIX, но универсально поддерживается .


Версия с правильным использованием ™ delete:

awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;delete a[i++]){print a[i]}}'

Версия без удаления, использующая больше памяти и размеров:

awk '{a[n][$1]=$0} !(NR%4){asort(a[n]); for(i=1;i<5;print a[n][i++]); n++}

1

Вы можете получить чистое решение с помощью R. Если приведенная выше таблица находится в файле с именем «table.txt», выполните следующие действия. Желаемый результат будет в файле "tableout.txt".

> x = read.table("table.txt", col.names=c("a", "b"))
> x
     a        b
1 6115  8.88443
2 6116  6.61875
3 6118 16.59490
4 6117 19.41290
5 6116  6.61900
6 6117 16.59790
7 6118 19.41110
8 6115  8.88433
> x["index"] = c(rep(1, 4), rep(2, 4))
> x
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
3 6118 16.59490     1
4 6117 19.41290     1
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
8 6115  8.88433     2     
> xord = x[with(x, order(index, a)), ]
> xord
     a        b index
1 6115  8.88443     1
2 6116  6.61875     1
4 6117 19.41290     1
3 6118 16.59490     1
8 6115  8.88433     2
5 6116  6.61900     2
6 6117 16.59790     2
7 6118 19.41110     2
> write.table(xord[,1:2], "tableout.txt", row.names=FALSE, col.names=FALSE)

Смотрите также Как сортировать dataframe по столбцам (ы) в R .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.