Ordenar bloques de líneas

12

Tengo un archivo que contiene 4n líneas. Aquí hay un extracto que contiene 8 líneas.

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

Lo que quiero hacer es ordenar un bloque, donde cada bloque consta de 4 líneas basadas en la primera columna. El resultado del extracto debe verse como se muestra a continuación.

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
fuente

Respuestas:

16

Una opción es usar para agregar un prefijo de número de serie inicial cada N líneas (N = 4 en su caso). Luego alimente el prefijo como la columna de clasificación primaria sort.

Ejemplo con N = 4:

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

Si esto es único y no desea aprender Python, Perl o Awk, puede ir con los comandos básicos splity sort.

Primero divide el archivo en trozos de 4 líneas con la -l opción:

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

Los sort -nordena por valor numérico de la primera columna (999 antes de 1234). -a 6debe cuidar un archivo con 26 ^ 6 * 4 líneas. my_prefix_debe ser algo exclusivo del directorio con el que trabaja.

Anthon
fuente
3

Puedes hacerlo con 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 funciona esto

  • -n-> ejecuta el código para cada línea de entrada (y coloca la línea actual $_)
  • -l -> agregar una nueva línea a la salida de cualquier print
  • -e -> ejecuta la siguiente cadena como código Perl
  • Cada línea se agrega a la matriz @a.
  • $.mantiene el número de línea actual y, a menos que ese número no sea congruente con cero módulo 4, seguimos trabajando. Si es congruente con cero módulo 4, hemos alcanzado una línea cuyo número es un múltiplo de 4 (el final de un bloque), en cuyo caso, clasificamos las entradas en @aorden numérico ascendente e imprimimos las entradas en la matriz ordenada unidos por una nueva línea a la salida estándar.
Joseph R.
fuente
2

Usando un 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
fuente
2

Aquí hay algunas awksoluciones "puras" :

Si los índices son siempre la misma secuencia entera incremental (6115-6119), como en sus datos de muestra, puede usar un "acceso directo" algorítmico:

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

Esto hace

  • Agregue todas las líneas a la matriz a, distribuidas en las posiciones de índice 6115-6119
  • En cada cuarta línea ( !(NR%4)), recorra el contenido de la matriz para imprimir en el orden deseado.

Si sus índices numéricos son siempre los mismos cuatro, pero no una secuencia entera incremental, tendrá que ordenar:

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

Nota: Esto es con GNU awk, otros pueden no ser compatibles asort.


Si cada bloque de cuatro pudiera tener diferentes ID numéricos:

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

Nota: TIL de @Gilles auto-respuesta (+2) este uso deleteno es (todavía) POSIX, pero es universalmente compatible .


Una versión con el uso correcto ™ de delete:

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

Una versión sin borrar, usando más memoria y dimensiones:

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

Puede obtener una solución limpia con R. Si la tabla anterior está en un archivo llamado "table.txt", realice los siguientes pasos. El resultado deseado estará en el archivo "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)

Ver también Cómo ordenar una trama de datos por columna (s) en investigación .

Faheem Mitha
fuente