Ordinamento di blocchi di linee


12

Ho un file che contiene 4n righe. Ecco un estratto da esso contenente 8 righe

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

Quello che voglio fare è ordinare un blocco, in cui ogni blocco è composto da 4 righe in base alla prima colonna. L'output dell'estratto dovrebbe apparire come mostrato di seguito.

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

Risposte:


16

Un'opzione è usare per aggiungere un prefisso di numero seriale iniziale ogni N righe (N = 4 nel tuo caso). Quindi inserire il prefisso come colonna di ordinamento principale in sort.

Esempio con N = 4:

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

7

Se questo è un una tantum e non si vuole imparare Python, Perl o awk, si può andare con la base splite sortcomandi.

Dividi prima il file in blocchi di 4 righe con l' -l opzione:

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

I sort -ntipi di valore numerico della prima colonna (999 prima 1234). -a 6dovrebbe occuparsi di un file con 26 ^ 6 * 4 righe. my_prefix_dovrebbe essere qualcosa di unico nella directory con cui lavori.


3

Puoi farlo 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

Come funziona

  • -n-> esegui il codice per ogni riga di input (e inserisci la riga corrente $_)
  • -l -> aggiungi una nuova riga all'output di any print
  • -e -> esegue la seguente stringa come codice Perl
  • Ogni riga viene aggiunta all'array @a.
  • $.contiene il numero di riga corrente e, a meno che quel numero non sia congruente con zero modulo 4, continuiamo a funzionare. Se è congruente a zero modulo 4, abbiamo raggiunto una riga il cui numero è un multiplo di 4 (la fine di un blocco), nel qual caso, @aordiniamo le voci in ordine numerico crescente e stampiamo le voci nella matrice ordinata uniti da una nuova riga all'output standard.

2

Usando una 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

2

Ecco alcune awksoluzioni "pure" :

Se gli indici hanno sempre la stessa sequenza di numeri interi incrementali (6115-6119), come nei dati di esempio, è possibile utilizzare un "collegamento" algoritmico:

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

Questo fa

  • Aggiungi tutte le linee all'array a, distribuite nelle posizioni di indice 6115-6119
  • Ogni 4a riga ( !(NR%4)), scorrere i contenuti dell'array per stampare nell'ordine desiderato.

Se i tuoi indici numerici sono sempre gli stessi quattro, ma non una sequenza intera incrementale, dovrai ordinare:

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

Nota: questo è con GNU awk, altri potrebbero non supportare asort.


Se ogni blocco di quattro potrebbe avere ID numerici diversi:

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

Nota: TIL dalla risposta automatica di @Gilles (+2) questo uso deletenon è (ancora) POSIX, ma universalmente supportato .


Una versione con l'uso corretto ™ di delete:

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

Una versione senza cancellazione, usando più memoria e dimensioni:

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

1

Puoi ottenere una soluzione pulita con R. Se la tabella sopra si trova in un file chiamato "table.txt", procedi come segue. Il risultato desiderato sarà nel file "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)

Vedere anche Come ordinare un dataframe dalla colonna (s) in R .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.