Tri des blocs de lignes

12

J'ai un fichier qui contient 4n lignes. En voici un extrait contenant 8 lignes

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

Ce que je veux faire, c'est trier un bloc, où chaque bloc se compose de 4 lignes en fonction de la première colonne. La sortie de l'extrait doit ressembler à celle ci-dessous.

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
la source

Réponses:

16

Une option consiste à utiliser pour ajouter un préfixe de numéro de série initial toutes les N lignes (N = 4 dans votre cas). Ensuite, insérez le préfixe comme colonne de tri principale dans sort.

Exemple avec N = 4:

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

Si c'est un cas unique et que vous ne voulez pas apprendre le python, le perl ou l'awk, vous pouvez utiliser les commandes de base splitet sort.

Divisez d'abord le fichier en morceaux de 4 lignes avec l' -l option:

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

Les sort -ntris par valeur numérique de la première colonne (999 avant 1234). -a 6devrait prendre soin d'un fichier avec 26 ^ 6 * 4 lignes. my_prefix_devrait être quelque chose d'unique au répertoire avec lequel vous travaillez.

Anthon
la source
3

Vous pouvez le faire avec 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

Comment ça marche

  • -n-> exécuter le code pour chaque ligne d'entrée (et mettre la ligne actuelle $_)
  • -l -> ajouter une nouvelle ligne à la sortie de tout print
  • -e -> exécuter la chaîne suivante en code Perl
  • Chaque ligne est ajoutée au tableau @a.
  • $.contient le numéro de ligne actuel et à moins que ce nombre ne soit pas congru à zéro modulo 4, alors nous continuons à travailler. S'il est congru à zéro modulo 4, nous avons atteint une ligne dont le nombre est un multiple de 4 (la fin d'un bloc), auquel cas, nous trions les entrées dans @al'ordre numérique croissant et imprimons les entrées dans le tableau trié rejoint par une nouvelle ligne à la sortie standard.
Joseph R.
la source
2

En utilisant un shell de type 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
la source
2

Voici quelques awksolutions "pures" :

Si les index sont toujours la même séquence entière incrémentée (6115-6119), comme dans vos exemples de données, vous pouvez utiliser un "raccourci" algorithmique:

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

Cela ne

  • Ajoutez toutes les lignes au tableau a, réparties aux positions d'index 6115-6119
  • Sur chaque 4ème ligne ( !(NR%4)), parcourez le contenu du tableau pour imprimer dans l'ordre souhaité.

Si vos index numériques sont toujours les quatre mêmes, mais pas une séquence entière incrémentée, vous devrez trier:

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

Remarque: Ceci est avec GNU awk, d'autres peuvent ne pas prendre en charge asort.


Si chaque bloc de quatre peut avoir des ID numériques différents:

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

Remarque: TIL de @Gilles auto-réponse (+2) dont cette utilisation deleten'est pas (encore) POSIX, mais universellement pris en charge .


Une version avec l'utilisation ™ correcte de delete:

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

Une version sans suppression, utilisant plus de mémoire et de dimensions:

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

Vous pouvez obtenir une solution propre avec R. Si le tableau ci-dessus se trouve dans un fichier appelé "table.txt", procédez comme suit. Le résultat souhaité sera dans le fichier "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)

Voir aussi Comment trier une colonne par dataframe (s) dans R .

Faheem Mitha
la source