Classificando blocos de linhas

12

Eu tenho um arquivo que contém 4n linhas. Aqui está um trecho dele contendo 8 linhas

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

O que eu quero fazer é classificar um bloco, em que cada bloco consiste em 4 linhas com base na primeira coluna. A saída do trecho deve parecer como mostrado abaixo.

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

Respostas:

17

Uma opção é usar o para adicionar um prefixo de número de série inicial a cada N linhas (N = 4 no seu caso). Em seguida, alimente o prefixo como a coluna de classificação principal sort.

Exemplo com N = 4:

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

Se este é um caso único e você não deseja aprender python, perl ou awk, pode usar os comandos basic splite sort.

Primeiro divida o arquivo em pedaços de 4 linhas com a -l opção:

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_*

Classifica sort -npor valor numérico da primeira coluna (999 antes de 1234). -a 6deve cuidar de um arquivo com 26 ^ 6 * 4 linhas. my_prefix_deve ser algo exclusivo para o diretório com o qual você trabalha.

Anthon
fonte
3

Você pode fazer isso com o 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

Como isso funciona

  • -n-> execute o código para cada linha de entrada (e insira a linha atual $_)
  • -l -> acrescente uma nova linha à saída de qualquer print
  • -e -> execute a seguinte string como código Perl
  • Cada linha é anexada à matriz @a.
  • $.mantém o número da linha atual e, a menos que esse número não seja congruente a zero no módulo 4, continuamos trabalhando. Se for congruente a zero no módulo 4, alcançamos uma linha cujo número é múltiplo de 4 (o final de um bloco); nesse caso, classificamos as entradas em @aordem numérica crescente e imprimimos as entradas na matriz classificada unidos por uma nova linha na saída padrão.
Joseph R.
fonte
2

Usando um shell tipo 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
200_success
fonte
2

Aqui estão algumas awksoluções "puras" :

Se os índices são sempre a mesma sequência inteira incremental (6115-6119), como nos dados da amostra, você pode usar um "atalho" algorítmico:

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

Isso faz

  • Adicione todas as linhas à matriz a, distribuídas nas posições de índice 6115-6119
  • Em cada quarta linha ( !(NR%4)), percorra o conteúdo da matriz para imprimir na ordem desejada.

Se seus índices numéricos são sempre os quatro mesmos, mas não uma sequência inteira incremental, você precisará classificar:

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

Nota: Isso ocorre com o GNU awk, outros podem não suportar asort.


Se cada bloco de quatro pudesse ter IDs numéricos diferentes:

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

Nota: TIL da resposta automáticadelete do @Gilles (+2) esse uso de (ainda) não é POSIX, mas é universalmente suportado .


Uma versão com o uso correto de delete:

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

Uma versão sem exclusão, usando mais memória e dimensões:

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

Você pode obter uma solução limpa com R. Se a tabela acima estiver em um arquivo chamado "table.txt", execute as seguintes etapas. O resultado desejado estará no arquivo "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)

Veja também Como classificar uma trama de dados de coluna (s) em R .

Faheem Mitha
fonte